Sunteți pe pagina 1din 1206

Sobre 10s autores

Subrahmanyam Allamaraju
Subrahmanyam Allamaraju es Ingeniero y trabaja desde hace afios para BEA Systems Inc. Trabaja en las ireas de tecnologias de empresa/distribuidas, modelos de objeto basados en XML y otras ireas relacionadas. Si desea mis informaci6n sobre sus actividades, inquietudes y otros trabajos, consulte su pigina Web enwww.Subrahmanyarn.com. Subrahmanyam desearia dar las gracias a Varaa por su colaboraci6n en las pruebas de c6digo (enfrentindose a estrictos plazos) y por compartir su frustration y su euforia.

Cedric Beust
Cedric Beust es ingeniero de software y trabaja para el equipo de EJB en BEA Systems Inc. H a participado en la puesta en marcha de la versi6n 2.0 del contenedor WebLogic EJB. Doctorado en Informitica por la Universidad de Niza, Francia. Antes de doctorarse. trabai6 , Dara Sun Microsvstems donde se centr6 principalmente en CORBA. A lo largo de 10s aiios,'~edric ha participado en diversas comisiones dedicadas, Sus intereses abarcan desde todo lo relacionado con la informitica por ejemplo, a EJB, CORBA y C + distribuida y la ingenieria de software en general, hasta aficiones como el golf, el squash, el tenis y el voleibol.

+.

John Davies
John Davies trabaja como Director Jefe de Tecnologia ( C T O ) para Century 24 Solutions Ltd. (C24), www.C24Solutions.corn, una compafiia de software con sede en Londres que ofrece soluciones basadas en Java y J2EE para el mercado financiero. El ultimo product0 de C24, Elektra, disefiado para proporcionar una unica visi6n de las transacciones financieras complejas, hace extensivo el uso de todas las tecnologias J2EE. John esti embarcado en la actualidad en el proyecto de BNP-Paribas a la cabeza del grupo Technology Consulting Grup, recornendando el uso de tecnologias para proyectos actuales y futuros de todo el mundo. John comenzo en el mundo de las tecnologias de la informaci6n a finales de 10s setenta trabajando en el area de hardware, mis tarde en ensambladores, en C , C + + en el afio 87 y finalmente en Java desde principios del 96. Trabaj6 durante catorce afios como asesor principalmente en el sector bancario. Diez de estos afios 10s pas6 fuera del Reino Unido en diversos paises, incluido Estados Unidos, Asia y gran parte de Europa, donde aprendi6 a hablar algunos idiomas. En el tiempo que le queda libre entre su trabajo y escribir, John imparte clases de Java y XML para Learning Tree y es editor ttcnico de su curso de EJB 2.0. Sus aficiones incluyen viajar, la fotografia, la guitarra clisica, pilotar avionetas, el buen vino, la buena cerveza, la comida picante y socializar. John quisiera dar las gracias a su compaiiero licenciado en Astronomia Steve Miller por corregir sus trabajos y le gustaria saludar a su madre y pedirle perd6n por lo ma1 que se comport6 en el colegio.

Una vez ma's, nada de esto hubiera sido posible sin el carilio y el apoyo de m i fantastica esposa Rachel, Siento mucho las noches que te ha tocado pasar sola y gracias por L u c y James, os quiero
Puede ponerse en contact0 con en John.Davies@C24Solutions.com.

Tyler Jewell
Tyler Jewell trabaja corno "predicador" para BEA Systems Inc., donde escribe y alaba sobre las tecnologias de empresa para programadores. Es un experto preparador y mentor, especializado en arquitecturas a gran escalade e-business. Tyler es el autor de 19 cursos de preparacion sobre tecnologias de e-business y ha impartido mis de 200 seminarios sobre tecnologia a clientes y public0 en general. Es co-autor del libro Mastering Enterprise

JavaBeans 2.0 (O'Reilly 2001) y en la actualidad trabaja en el proyecto Java Web Services (O'Reilly 2002).
Tyler mantiene una columna habitual sobre J2EE en www.onjava.com, es miembro de la editorial O'Reilly's Editorial Masthead y es asesor de la pigina www.theserverside.com, Tu Comunidad J2EE. Tyler dedica su tiempo libre a su familia y amigos. Su afici6n favorita es el pdquer Texas Hold 'Em en el que dos cartas cualquiera pueden ganar, per0 siempre que caigan en sus manos.

Rod Johnson
Rod Johnson es arquitecto de Java de empresa especializado en aplicaciones Web reajustables. Ha pasado 10s dos dltimos arios diseriando una soluci6n J2EE para FT .corn, el portal de empresa mis grande Europa y en la actualidad esti escribiendo un libro para Wrox Press sobre diserio y desarrollo de J2EE. Despues de sus estudios, en 10s que se especializ6 en musica e informitica, Rod r e a h 6 un doctorado en musicologia antes de volver a dedkarse a1 desarrollo de software. Rod ha trabajado con Java tanto en ireas de cliente como en ireas de senidor desde su lanzamiento y se ha centrado en el desarrollo de Internet desde 1996. Su principal inter& es la arquitectura JZEE, EJB y el desarrollo Web 00. Rod reparte su tiempo entre Londres y Sydney, y le gusta el tenis, el esqui, la historia y tocar el piano. Puede ponerse en contacto con el en rod.johnson@interface21.com.

Gracias a Keriy por su amor y su apoyo, ahora que comenzamos nuestra nueva aventura.

Andy Longshaw
Andy Longshaw es asesor independiente, escritor y educador especializado en JZEE, XML, tecnologias y componentes de base Web, en particular en las decisiones de diserio y arquitectura necesarias para utilizar estas tecnologias satisfactoriamente. Andy ha estado explicando tecnologia durante la mayor parte de la ultima decada en sus funciones principales de Director de Tecnologia de Content Master Ltd. y Q A Training. Tambien ofrece conferencias sobre JZEE, XML y arquitecturas de componentes de grada media. Circula un rumor sin confirmar que dice que algunas personas consiguen no dormirse durante estas sesiones. Esti dispuesto a responder a cualquier comentario, pregunta o critica sobre el capitulo de diserio que ha escrito para este libro en la pigina www.blueskyline.com.

A Sarah, Adam y Joshua que son la inspiracidn de todo lo que hago, y a rnis padres que se aseguraron de que yo recibiera una educacidn lo suficientemente buena como poder escribir este libro.

Ramesh Nagappan
Ramesh Nagappan es Arquitecto de Tecnologia especializado en Java y en arquitecturas de aplicacidn de distribucidn de base CORBA. Es un predicador de Java y tambien un activo contribuyente a las especificaciones e implementaciones de fuente abierta. Antes de enpncharse a Java y a CORBA, trabaj6 como ingeniero de Investigacidn para desarrollar soluciones CAD/CAM y de dinimica de fluidos computational para aplicaciones aeroespaciales. En su tiempo libre le gusta disfrutar de 10s deportes de agua y jugar con hijo Roger. Puede encontrarle en su direcci6n de correo nramesh@mediaone.net.
ils

Dedicado a mi esposa Joyce y a nuestro hijo Roger, por su carifio, apoyo e inspiracidn, y tambie'n a rnis queridos padres por alegrar m i vida.

Dr. P. G. Sarang
Como contratista de Sun Microsystems, el Dr. Sarang forma a 10s clientes de la compafiia con diversos cursos del programa oficial de Sun. Tambien dirige el programa "Formar a formadores" y las "Pruebas de autorizacidn de instructores" en representacidn de Sun.

Como Director Jefe Ejecutivo ( C E O ) de A B C O M Information Systems Pvt. Ltd, el Dr. Sarang esti especializado en formacidn y en el desarrollo de proyectos sobre la plataforma Java/CORBA. Con casi 20 aiios de experiencia en el sector, el Dr. Sarang ha desarrollado diversos productos y ha completado con Cxito varios proyectos industriales. Es orador habitual en muchas conferencias de Lmbito nacional e internacional y contribuye regularmente con articulos tecnicos a la edicidn de revistas y diarios de tirada internacional. Sus intereses actuales incluyen la plataforma .NET y C#.

Me gustaria dedicar este libro a m i madre por su constante apoyo y paciencia.

Alex Toussaint
Alex Toussaint es Director de Ingenieria para Vignette Corporation en Austin, Texas. Cuenta con mas de diez afios de experiencia en desarrollo de software y tiene una amplia experiencia en el manejo de Java desde 1996 y de las tecnologias J2EE desde 1998. Alex ha colaborado en articulos sobre aplicaciones Web y comercio electrdnico para revistas on-line, tales como Microsoft M S D N , y es coautor del libro Professional Site Server publicado por Wrox. Alex tambiin ha sido invitado a impartir clases en la Universidad de Texas en Austin Red McCombs School of Business sobre temas como Comercio Electrdnico y Desarrollo de Software de Empresa. Alex reside en Austin, Texas, en la actualidad con su esposa Danielle y su perro Sasha. Alex e s t i a su disposicidn en la direcci6n alex~toussaint@yahoo.com.

Sameer Tyagi
Sameer escribe regularmente para publicaciones on-line e impresas. Cuenta con mas de cuatro afios de experiencia en diseiio y desarrollo de software y esti especializado en aplicaciones distribuidas de lado del servidor de base Java (arquitecturas n-Grada, JDBC, JNDI, EJB, JMS, RMI, JSP, Servlets, et al.). Es licenciado en Ingenieria Electrdnica y tiene una amplia formacidn sobre el tema. Es un adicto a Java y consigue su dosis saltando de cabeza a casi cualquier cosa que se compila en c6digos de bytes y se le conoce como el culpable de esa nueva area del cerebro Ilamada Javaesfera por dichos estimulos. Cuando no estC disfrutando de un cafC, puede encontrarle volando a unos 15000 pies de altura en una pequeria Cessna.

Gary Watson
Gary Watson ha estado desarrollando el uso de Java durante 10s ultimos 4 arios. Es asesor independiente de Tecnologias de la Informacidn y, en la actualidad, trabaja como Arquitecto TCcnico en el Financial Times, FT. com, en el desarrollo de una importante soluci6n J2EE. Graduado por la Universidad de Teeside en 1993, Gary es Licenciado en Ciencias de la Informltica. Siempre que le es posible, Gary disfruta del windsurf, del esqui y de 10s aviones en miniatura. N o participa en estas actividades tan a menudo como le gustaria. Puede encontrarle en Gary@comcontracts.demon.co.uk.

A m i esposa Angela por su amor, apoyo y aliento mientras luchamos juntos en la vida diaria.

Marc Wilcox
Marc trabaja en el grupo de servicios profesionales de W e b C T Inc., la principal compafiia del mundo de desarrollo de Sistemas de Gestidn/Entornos de Aprendizaje Virtual. La prdxima version de su producto, cuyo nombre en clave es Cobalt, estari basada en un entorno de aplicaci6n J2EE.

Me gustaria dedicar este libro a Doug y a Sammy, 10s mejores peluqueros del mundo.

Alan Williamson
Alan Williamson es todo un veterano del mundo Java, con un lenguaje que todavia intenta encontrar su lugar en el mundo. Alan cuenta con mis de 15 ahos de experiencia en el mundo del desarrollo de software. Se graduo con Honores en Ciencias de la Informitica por la Universidad de Paisley. Alan trabaj6 principalmente en tareas de investigaci6n y desarrollo hasta que establecio la primera compahia del Reino Unido dedicada Gnicamente a1 asesoramiento en Java hace 4 ahos, especializandose en Java en lado del servidor (http://www.n-ary.com). Alan t a m b i h ha llegado hasta lo mis alto convirtihdose en Editor Jefe de la revista mis importante del mundo sobre Java, Java Developers Journal y puede encontrarle dando conferencias por todas partes.

Me gustaria dar las gracias a m i querida Ceri y a m i nuevo hijo Cormacpor guardar el fuerte mientras yo trabajaba e investigaba para escribir este capitulo. Buen trabajo. Adernas, me gustaria dar lax gracias a Keith y Marion por realizar sus tareas de profesor y leer m i capitulo corrigiendo mis errores de gramatica. Finalmente, me gustaria dar las gracias a Wrox por hacer de este proceso de escritura algo alegre y no algo doloroso.

Introduccion

37

J2EE Edici6n 1.3 .......................................................................................................................................... 37 iQuk ha cambiado en esta edicion del libro? ....................................................................................... 38 ?A quiin va dirigido este libro? ................................................................................................................ tCubles son 10s contenidos de este libro? ...............................................................................................
38 39

Lo necesario para utilizar este libro ......................................................................................................... 39 Contenedor Web ............................................................................................................................. 39 Contenedor EJB .............................................................................................................................. 39 Bases de datos ................................................................................................................................... 39 Software adicional .......................................................................................................................... 40

.............................................................................................................................................. Atenci6n a1 cliente .................................................................................................................................... C6mo cargar el c6digo de muestra para el libro .................................................................................... Erratas ........................................................................................................................................................... Apoyo via e-mail ......................................................................................................................................... p2p.wrox.com ..............................................................................................................................................
Convenciones iPor quk esre sistema ofrece el rnejor apoyo?

40 41 41 41 41 42

..................................................................................... 42

Capitulo 1 Plataforma JZEE


Programac~on para empresas .....................................................................................................................

45
46

..

La empresa actual ........................................................................................................................................ 46 iEs Java la respuesta? ............................................................................................................................. 49 Independiente de la plataforma ....................................................................................................... 49 Objetos gestionados ........................................................................................................................ 49 Reusabilidad ...................................................................................................................................... 49 Modularidad ...................................................................................................................................... 50

Estilos de arquitectura de empresa 50 Arquitectura de dos niveles ................................................................................................................... 50 Arquitectura de tres niveles ................................................................................................................... 51 52 Aquitectura de n niveles ....................................................................................................................... Arquitectura de empresa ........................................................................................................................ 53 La plataforma JZEE ..................................................................................................................................... 55 Period0 de ejecuci6n de J2EE ............................................................................................................... 55 Los API de J2EE .................................................................................................................................... 56 Contenedores ........................................................................................................... 58 Arquitectura JZEE . Arquitectura de contenedor ....................................................................................................................... 60 Contratos de componentes ............................................................................................................ 61 API de servicio de contenedor ....................................................................................................... 62 63 Servicios declarativos ....................................................................................................................... Otros servicios de contenedor ....................................................................................................... 65 Tecnologias JZEE 65 Tecnologias de componentes ................................................................................................................ 66 Componentes Web .......................................................................................................................... 66 Componentes Enterprise JavaBean ............................................................................................... 67 XML ........................................................................................................................................................ 68 ......................................................................................................................... 69 Tecnologias de servicio . JDBC ................................................................................................................................................ 69 Java Transaction API y Servicio .................................................................................................... 69 JMS .................................................................................................................................................... 70 JavaMail ............................................................................................................................................ 70 lava Conector Architecture ............................................................................................................ 70 70 JAAS ................................................................................................................................................. 70 Tecnologias de comunicaci6n ............................................................................................................... 70 Protocolos de Internet .................................................................................................................... TCPIIP .............................................................................................................................................. 71 SSL ...................................................................................................................................................... 71 71 Protocolos de objeto remoto ......................................................................................................... Desarrollo de aplicaciones JZEE 71 . . Funciones de desarrollo e implementaci6n de apl~caclones ................................................................ 72 Desarrollo de componentes de aplicaci6n ........................................................................................... 73 Composici6n de componentes de aplicaci6n en m6dulos ................................................................ 73 Composicibn de m6dulos en aplicaciones ........................................................................................... 73 74 Implementaci6n de la aplicaci6n ........................................................................................................... Resumen .......................................................................................................................................................
75

..........................................................................................................

.........................................................................................................................................

...............................................................................................................

Canitulo 2 Servicios de directorio y JNDl


Servicios de designaci6n y de directorio 77 Servicios de designaci6n ........................................................................................................................ 78 Servicios de directorio ........................................................................................................................... 79 80 LDAP ...................................................................................................................................................... Datos LDAP .................................................................................................................................... 81

.................................................................................................

Las concesiones ................................................................................................................................ 85 85 iPor qu6 utilizar J N D I cuando tenemos LDAP? ......................................................................... LDAP sin J N D I ................................................................................................................................ 86 86 J N D I sin LDAP ................................................................................................................................ iY XML? ............................................................................................................................................ 86 Uso de J N D I ............................................................................................................................................... 86 Instalaci6n de J N D I .............................................................................................................................. 87 Proveedores de servicios J N D I 87 88 C6mo obtener poveedores de semicios J N D I .................................................................................. 88 C o m o desarrollar su propio proveedor de servicios .......................................................................... Java y LDAP 89 Control de acceso .................................................................................................................................. 89 Autentificacion ................................................................................................................................. 89 90 Autorizaci6n .................................................................................................................................... 90 Semicios de piginas blancas .................................................................................................................. 91 Directorio de procesamiento distribuido ............................................................................................ Configuraci6n de la aplicaci6n ........................................................................................................ 91

.................................................................................................................

.................................................................................................................................................

Operaciones LDAP ..................................................................................................................................... 92 92 Operaciones LDAP estindar ................................................................................................................ 92 Conexion a1 semidos LDAP con J N D I .............................................................................................. 93 Asociacion .............................................................................................................................................. 94 Seguridad simple, SSL/TLS y SASL ................................................................................................ 94 Simple .................................................................................................................................................

95 SASL ................................................................................................................................................... 95 Autentificacion en LDAP v2 y LDAP v3 ...................................................................................... 95 Busqueda en u n s e n i d o r LDAP 96 Filtros LDAP de ejemplo ...................................................................................................................... 96 Determinar el alcance de LDAP ........................................................................................................... LDAP-SCOPE-SUBTREE ........................................................................................................... 96 LDAP-SCOPE-ONELEVEL ....................................................................................................... 97 LDAP-SCOPE-BASE .................................................................................................................... 97 Ejecucion de una b6squeda J N D I ......................................................................................................... 98 100 Cbmo funciona el programa de bhqueda .................................................................................... Restringir 10s atributos presentados .................................................................................................. I03 Aiiadir entradas .................................................................................................................................... 105 111 Modificar una entrada .......................................................................................................................... 113 Eliminar una entrada ........................................................................................................................... Almacenar y recuperar objetos Java en LDAP ....................................................................................... 114 115 LDAP tradicional ........................................................................................................................... 116 Java serializado .............................................................................................................................. Referencias Java .............................................................................................................................. 116 116 Volver a J N D I sin LDAP Ejemplo de aplicacidn D N S ................................................................................................................. 117

...............................................................................................................

.........................................................................................................................

lndice
Resumen

.....................................................................................................................................................

119

Capitulo 3 Procesamiento distribuido con RMI

121

La arquitectura RMI ................................................................................................................................. 122 Capa de Stub y Skeleton ....................................................................................................................... 123 Stubs ................................................................................................................................................ 124 Skeletons ......................................................................................................................................... 124 Capa de referencia remota ................................................................................................................... 125 Capa de transporte ............................................................................................................................... 125 Localizaci6n de objetos remotos ............................................................................................................ 126 Archivos de politica ...................................................................................................................... 128 Excepciones RMI ..................................................................................................................................
129

Desarrollo de aplicaciones con RMI ...................................................................................................... 130 Definir la interfaz remota ............................................................................................................ 131 Implementar la interfaz remota .......................................................................................................... 131 Grabar el cliente que utiliza 10s objetos remotos ......................................................................... 133 Generar stubs y skeletons ................................................................................................................... 134 Registrar el objeto ................................................................................................................................ 134 Ejecutar el cliente y el servidor ........................................................................................................... 135 Pasar parimetros e n RMI ......................................................................................................................... 136 Parimetros de primitivas ..................................................................................................................... 136 Parimetros de objeto ........................................................................................................................... 136 Parimetros remotos ............................................................................................................................ 137

.................................................................................................. Clases de carga dinimica ..................................................................................................................... Retrollamadas remotas ............................................................................................................................ Activaci6n de objeto ...............................................................................................................................
El recolector de residuos distribuidos

138 141 146

149 El grupo de activaci6n ......................................................................................................................... 150 ActivationID .................................................................................................................................. 151 Descriptor de activacion ................................................................................................................ 152 Convertir objetos en activables ......................................................................................................... 153 Paso 1: Crear la interfaz remota .............................................................................................. 154 Paso 2: Crear la implementacih del objeto .........................................................................154 Paso 3: Registrar el objeto con el sistema ...............................................................................154 Alternativa a ampliar la clase Activatable ..................................................................................... 156 Iniciar mGltiples JVMs sin recurrir a rmid ..............................................................................157 Desactivaci6n ....................................................................................................................................... 159 160

................................................................................................................... RMI. cortafuegos y H T T P .......................................................................................................................


Sockets de adaptaci6n y SSL

172 Tunelado HTTP ................................................................................................................................... 172 H T T P a puerto ............................................................................................................................... 172 H T T P a C G I .................................................................................................................................. 173

lndice
El protocolo SOCKS ..................................................................................................................... 173 174 Factorias de sockets descargados ........................................................................................................ RMI sobre I I O P ........................................................................................................................................ 174 175 Interoperatividad con CORBA .................................................................................................... 176 Escribir programas con RMI-HOP ............................................................................................... 176 En el servidor ................................................................................................................................. 176 HelloServer.java ............................................................................................................................... 177 En el cliente ................................................................................................................................... 177 HelloClient.java ............................................................................................................................... 180 RMI-IIOP y Java IDL 180 El archivo IDL ............................................................................................................................... 180 La implernentacion de servidor ..................................................................................................... 182 La implementacibn cliente ............................................................................................................. RMI-IIOP y J2EE ..................................................................................................................................... 184 Ajustar aplicaciones RMI ......................................................................................................................... 185 Resumen ..................................................................................................................................................... 189

..............................................................................................................................

Capitulo 4 Programacion de bases de datos con JDBC


Drivers de bases de datos ..................................................................................................................... 193 Puente JDBC-ODBC .......................................................................................................... 193 Tipo 1 . Parte Java, parte driver nativo ............................................................................................. 194 Tipo 2 . Servidor intermediario de acceso a bases de datos ............................................................. 195 Tipo 3 . Drivers Java puro ................................................................................................................ 196 Tipo 4 . 196 Cdmo comenzar ..................................................................................................................................

El paquete java.sq1 ...................................................................................................................................... 197 197 Gesti6n de conexion ........................................................................................................................... 198 Acceso a bases de datos ....................................................................................................................... 198 Tipos de datos ...................................................................................................................................... 199 Metadatos de base de datos .................................................................................................................. 200 Excepciones y advertencias ................................................................................................................. 201 Cargar un driver de base de datos y abrir conexiones ...................................................................... 201 Los URL de JDBC ......................................................................................................................... DriverManager ............................................................................................................................... 202 203 Mitodos para gestionar drivers ...................................................................................................... 203 Mitodos para obtener conexiones ................................................................................................. 204 MCtodos de registro ........................................................................................................................ 205 Driver .............................................................................................................................................. 205 Establecer una conexion ...................................................................................................................... 208 Crear y ejecutar instrucciones SQL ................................................................................................... 209 U n ejemplo: catdogo de peliculas ................................................................................................. 210 Crear la tabla Movie ........................................................................................................................ 210 Insertar datos .................................................................................................................................. 211 Mitodos para el manejo de excepciones ......................................................................................... 214 Consultar la base de datos ................................................................................................................... 214 Mktodos para recuperar datos ........................................................................................................ Interfaz ResultSetMetaData ............................................................................................................ 216

Instrucciones preparadas ..................................................................................................................... 217 219 Representar tipos S Q L en Java ........................................................................................................... 221 Apoyo a transacciones ....................................................................................................................... 223 Puntos de salvaguardia ......................................................................................................................... Listas de resultados desplazables y actualizables ................................................................................ 225 225 Listas de resultados desplazables ................................................................................................... Metodos relacionados con la posici6n del cursor ......................................................................... 227 227 Metodos para desplazamiento ........................................................................................................ 227 Direcci6n y tamafio de toma .......................................................................................................... Listas de resultados actualizables .................................................................................................. 230 230 Actualizar una fila ............................................................................................................................ Eliminar una fila .............................................................................................................................. 231 231 Insertar una fila ............................................................................................................................... Actualizaciones de lotes ....................................................................................................................... 231 El paquete javax.sql

.................................................................................................................................... Fuentes de datos JDBC ............................................................................................................................

232

234 La interfaz javax.sql.DataSource ......................................................................................................... 234 El mCtodo getconnection() ......................................................................................................... 234 235 El metodo getLoginTimeout() ..................................................................................................... 235 El metodo setLoginTimeout() ............................................................................................... El metodo getlogwriter() ........................................................................................................... 235 235 El metodo setlogwriter() ............................................................................................................ J N D I y fuentes de datos ...................................................................................................................... 236 237 Crear una fuente de datos .............................................................................................................. Recuperar un objeto Datasource .................................................................................................. 238 Caracteristicas clave ....................................................................................................................... 238 239 Revisi6n del catilogo de peliculas .......................................................................................................

240 Reserva de conexiones Resewa de conexiones tradicional ...................................................................................................... 241 243 Resewa de conexiones con el paquete javax.sq1 ........................................................................... La interfaz javax.sql.ConnectionPoolDataSource...................................................................... 244 244 La interfaz javax.sql.PooledConnection ...................................................................................... .......................................................................... 245 La interfaz javax.sql.ConnectionEventListener La clase javax.sq1.ConnectionEvent ............................................................................................. 245 245 Implementaci6n de reservas de conexi6n ............................................................................. 246 Transacciones distribuidas i Q d es una transacci6n? .................................................................................................................... 246 247 Antecedentes ........................................................................................................................................ 248 Procesamiento de transacciones - Conceptos ........................................................................... 248 Demarcaci6n de transacciones ..................................................................................................... 249 Contexto de transacciones y propagaci6n ............................................................................. 249 Alistamiento de recursos ............................................................................................................... Aceptar en dos fases ...................................................................................................................... 249 Construcci6n de bloques de sistemas de procesamiento de transacciones .....................................250 250 Componentes de aplicaci6n .......................................................................................................... 250 Gestores de recursos ..................................................................................................................... Gestor de transacciones ................................................................................................................ 251 251 Transacciones distribuidas JDBC ......................................................................................................

.............................................................................................................................

......................................................................................................................

La interfaz javax.sq1.XADataSource ............................................................................................. 252 La interfaz javax.sql.XAConnection ............................................................................................ 252 La interfaz javax.Transaction.UserTransaction ......................................................................... 252 Pasos para la irnplementaci6n de transacciones distribuidas ............................................................ 253 Configuraci6n ................................................................................................................................ 254 Iniciar una transacci6n .................................................................................................................. 254 Operaciones de base de datos ....................................................................................................... 254 Finalizar una transaction .............................................................................................................. 255 Precauciones especiales .................................................................................................................. 255

Objetos RowSet 256 La interfaz javax.sql.RowSet ............................................................................................................... 257 Propiedades ..................................................................................................................................... 257 Eventos ........................................................................................................................................... 258 Ejecuci6n de comandos y resultados ............................................................................................ 258 Tipos de objetos RowSet ..................................................................................................................... 258 La implementacidn CachedRowSet .................................................................................................... 259 La implementacidn RowSet JDBC ..................................................................................................... 261 La implementacidn RowSet Web ........................................................................................................ 261 Resurnen .....................................................................................................................................................
262

.........................................................................................................................................

Capitulo 5 Introduccion a 10s contenedores Web


El protocolo H T T P 266 MCtodos de solicitud H T T P ............................................................................................................... 266 El metodo de solicitud GET ......................................................................................................... 266 El mitodo de solicitud POST ....................................................................................................... 267 El metodo de solicitud H E A D ..................................................................................................... 267 La respuesta H T T P ............................................................................................................................. 267

..................................................................................................................................

Contenedores Web y aplicaciones Web 268 Sewlets Java .......................................................................................................................................... 269 Piginas JavaServer ............................................................................................................................... 272 Descriptores de despliegue .................................................................................................................. 273 Estructura de aplicaciones Web .......................................................................................................... 274 Tipos de contenedores Web ................................................................................................................ 274

..................................................................................................

Una sencilla aplicaci6n Web 275 Prepara el contenedor Web ................................................................................................................. 275 Crear el archivo H T M L ...................................................................................................................... 275 Crear un servlet .................................................................................................................................... 276 Construir la aplicacion Web ................................................................................................................ 277 Desplegar la aplicaci6n Web ............................................................................................................... 281 Ejecutar la aplicaci6n Web ................................................................................................................... 283 C6mo funciona la aplicaci6n ............................................................................................................... 283 El servlet Greeting ......................................................................................................................... 284 Importar 10s paquetes de servlet ..................................................................................................... 284 Declaraci6n de clase ......................................................................................................................... 285 Revisar la solicitud POST HTTP ................................................................................................... 285 Extraer parametros de HttpServletRequest ................................................................................... 285 Generar respuesta ............................................................................................................................ 285

....................................................................................................................

El descriptor de despliegue

............................................................................................................ 287
288

Resumen .....................................................................................................................................................

Capitulo 6 Programacion de servlets


Analisis del API Java Servlet

................................................................................................................. Implementacidn de servlet ......................................................................................................................

292

296 La interfaz servlet ................................................................................................................................ 296 El metodo init () ............................................................................................................................. 297 297 El metodo service() ....................................................................................................................... El metodo destroy() ...................................................................................................................... 297 El metodo getServletConfig() ...................................................................................................... 298 El metodo getServletInfo() .......................................................................................................... 298 La clase GenericServlet ........................................................................................................................ : La interfaz SingleThreadModel .......................................................................................................... La clase HttpServlet ............................................................................................................................. Los metodos service() ................................................................................................................... Los metodos doXXX() ................................................................................................................. El metodo getLastModified() .......................................................................................................

Configuracidn de servlets La interfaz ServletConfig .................................................................................................................... El metodo getInitParameter() ...................................................................................................... El metodo getInitParameterNames() .......................................................................................... El metodo- getServletContext () .................................................................................................... El mitodo getServletName0 ........................................................................................................ Obtener una referencia a ServletConfig ............................................................................................ Durante la inicializaci6n del servlet .............................................................................................. Utilizar el metodo getServletConfig() ......................................................................................... Excepciones servlet La clase ServletException .................................................................................................................... La clase UnavailableE~ce~tion ............................................................................................................

........................................................................................................................

...................................................................................................................................

................................................................................................................. El ciclo de vida de u n servlet . FreakServlet .........................................................................................


El ciclo de vida de 10s servlets

Instanciaci6n ........................................................................................................................................ Inicializaci6n ........................................................................................................................................ Servicio ................................................................................................................................................. Destruir ................................................................................................................................................

Solicitudes y respuestas Lainterfaz ServletRequest ................................................................................................................... Metodos para solicitar parametros .................................................. : ............................................ El mktodo getparameter() .............................................................................................................. 319 319 El metodo getParameterValues() ................................................................................................... El metodo getParameterNames0 .................................................................................................. 320 320 El mktodo getParameterMap0 ................................................................................................. Metodos para atributos de solicitud ............................................................................................. 320 El metodo getAttribute() ................................................................................................................ 320

...........................................................................................................................

El metodo getAttributesNames() .................................................................................................. 320 El metodo setAttribute() ................................................................................................................ 320 El metodo removeAttribute0 ........................................................................................................ 320 Metodos de entrada ....................................................................................................................... 321 El metodo getInputStream() .......................................................................................................... 321 El metodo getReader() .................................................................................................................... 321 El metodo getCharacterEncoding0 .............................................................................................. 321 El metodo setCharacterEncoding() .............................................................................................. 321 La clase ServletRequestWrapper ......................................................................................................... 321 La interfaz HttpServletRequest .......................................................................................................... 321 Metodos para solicitar ruta y URL ............................................................................................... 323 El metodo getPathInfo0 ................................................................................................................ 323 El metodo getPathTranslatedO ...................................................................................................... 323 El metodo getQueryString() .......................................................................................................... 324 El metodo getRequestURI0 .......................................................................................................... 324 El metodo getRequestURL0 .......................................................................................................... 324 El metodo getsewletpath() ............................................................................................................ 324 Metodos para cabeceras HTTP ..................................................................................................... 324 El m6todogetHeaderO .................................................................................................................... 324 El metodo getHeaders() ................................................................................................................. 324 El metodo getHeaderNames0 ....................................................................................................... 324 El metodo getMethod() ................................................................................................................ 324 La~laseHtt~ServletRequestWrapper .......................................................................................... 325 La interfaz ServletResponse ................................................................................................................ 325 Metodos para tip0 de contenido y longitud ................................................................................ 325 El metodo setContentType() .................................................................... .................................... 325 El metodo setcontentlength() ..................................................................................................... 325 Metodos de salida ........................................................................................................................... 326 El metodo getOutputStream() ....................................................................................................... 326 El metodo getwriter() .................................................................................................................... 326 Metodos para salida en bfifer ........................................................................................................ 326 El metodo setBufferSize0 .............................................................................................................. 326 El mktodo getBufferSize0 .............................................................................................................. 326 El metodo resetBuffer() ................................................................................................................. 326 El metodo flushBuffer() ................................................................................................................. 327 El metodo isCommitted() .............................................................................................................. 327 El metodo reset() ............................................................................................................................ 327 La clase ServletResponseWrapper ...................................................................................................... 327 La interfaz H t t p S e w l e t R e ~ ~ o n s ....................................................................................................... e 327 MCtodos para el manejo de errores .............................................................................................. 328 El metodo sendError() .................................................................................................................. 328 El metodo sendError() .................................................................................................................. 328 El metodo setstatus() ..................................................................................................................... 328 El metodo sendRedirect() ............................................................................................................. 328 La clase HttpServletResponseWrapper .............................................................................................. 328 Funci6n de las clases envoltorio ......................................................................................................... 328

Programacidn de servlets . Aplicacidn de apoyo tkcnico ................................................................... 329

Configurar la pigina HTML ......................................................................................................... 330 Preparar la base de datos ................................................................................................................ 332

Escribir el servlet ........................................................................................................................... 333 Extraer datos del formulario .......................................................................................................... 334 Insertar la solicitud de apoyo tecnico ............................................................................................. 334 335 Generar la respuesta ........................................................................................................................ Compilar la fuente ....................................................................................................................... 336 Construir la aplicaci6n Web .......................................................................................................... 336 340 El descriptor de despliegue .............................................................................................................. 340 Configurar la fuente de datos ....................................................................................................... Desplegar la aplicaci6n Web ......................................................................................................... 341 Apoyo tecnico en marcha ............................................................................................................. 344 Resumen .................................................................................................................................................... 346

Capitulo 7 Sesiones de servlets. context0 y colaboracion


Protocolo sin estado y sesiones

349
350

.............................................................................................................. Enfoques del registro de sesi6n ..............................................................................................................


..

352 Reescritura de URL .............................................................................................................................. 353 Campos de formulario ocultos ........................................................................................................... 354 Cookies ................................................................................................................................................. 354

Registro de seslon con el API Java S e n l e t 356 Creaci6n y registro de sesiones .......................................................................................................... 357 357 La interfaz HttpSession ...................................................................................................................... Metodos para vida de sesion ......................................................................................................... 358 El metodo getCreationTime0 ........................................................................................................ 359 El mitodo getId() ........................................................................................................................... 359 El mitodo getLastAccessedTime() ................................................................................................. 359 El mitodo getMaxInactiveInterval() ............................................................................................. 359 El metodo setMaxInactiveInterval() ............................................................................................. 359 El metodo isNew() ......................................................................................................................... 359 360 El metodo invalidate() .................................................................................................................... 360 Demostrar el ciclo de vida de la sesion con cookies ................................................................... Ciclo de vida de sesion sin cookies .............................................................................................. 364 365 Metodos para gestionar el estado ................................................................................................. El metodo getAttribute() ................................................................................................................ 365 El metodo getAttributeNames0 .................................................................................................... 365 El mCtodo setAttribute() ................................................................................................................ 365 366 El metodo removeAttribute() ........................................................................................................ Demostrar la gesti6n de estado .................................................................................................... 366 Manejo de eventos de ciclo de vida de sesi6n .................................................................................... 369 369 La interfaz HttpSessionListener .................................................................................................. La interfaz HttpSessionActivationListener ................................................................................ 370 El mitodo sessionDidActivate() .................................................................................................... 370 370 El metodo sessionWillPassivate() .................................................................................................. 370 La clase HttpSessionEvent ............................................................................................................ El mCtodo getsession() .................................................................................................................. 370 Manejo de eventos de atributos de sesi6n ......................................................................................... 371 371 La interfaz HttpSessionBindingListener..................................................................................... El metodo valueBound() ................................................................................................................ 371 El metodo valueUnbound() ........................................................................................................... 371

.........................................................................................

La interfaz HttpSessionAttributeListener ................................................................................... 371 El metodo attributeAdded0 ........................................................................................................... 372 El metodo attributeRemoved0 ...................................................................................................... 372 El metodo attributeReplaced0 ........................................................................................................ 372 La clase HttpSessionBindingEvent .............................................................................................. 372 El mitodo getName() ..................................................................................................................... 372 El mitodo getvalue() ...................................................................................................................... 372 El metodo getsession() .................................................................................................................. 372 U n sencillo carro de la compra utilizando sesiones ........................................................................ 372 El senlet del catilogo .................................................................................................................... 373 El senlet Shoppingcart ................................................................................................................ 374 Contexto de sewlet ................................................................................................................................... 377 La interfaz Senletcontext .................................................................................................................. 378 El mttodo getMimeType0 .............................................................................................................. 378 El mttodo getResource0 ................................................................................................................ 378 El metodo getResourceAsStream() ............................................................................................... 378 El metodo getRequestDispatcher() ................................................................................................ 379 El metodo getNamedDispatcher ................................................................................................. 379 El metodo getRealPath0 ................................................................................................................ 379 El metodo getcontext () ................................................................................................................. 379 El mitodo getSenerInfo() ............................................................................................................. 379 El metodo getSenletcontextName() ............................................................................................ 379 El metodo getResourcePaths() ...................................................................................................... 379 Los metodos getInitParameter0 y getInitParameterNames() .................................................... 380 Los metodos getAttribute0, getAttributeNames0, setAttributes0 y removeAttribute0 ........380 Los metodos log() .......................................................................................................................... 380 El manejo de eventos de ciclo de vida de Senletcontext .............................................................. 380 La interfaz Senlet Context Listener .............................................................................................. 380 SenletContextAttributeListener.................................................................................................. 381 Una aplicacion de chat que utiliza context0 y sesiones ..................................................................381 La clase ChatRoom ........................................................................................................................ 384 La clase ChatEntry ........................................................................................................................ 384 El senlet de administracion .......................................................................................................... 385 Servlets para chat .......................................................................................................................... 388 La clase ListRoomsSenlet .............................................................................................................. 388 La clase ChatRoomSenlet .............................................................................................................. 391 Configuration del chat .................................................................................................................. 396 Una pigina de bienvenida ................................................................................................................ 396 Descriptor de despliegue ................................................................................................................. 396 Desplegar y probar .......................................................................................................................... 397 Colaboracion de sewlet ............................................................................................................................ 399 Encadenado de senlet ................................................................................................................... 399 Lanzamiento de solicitudes ........................................................................................................... 400 La interfaz RequestDispatcher ...................................................................................................... 400 El metodo forward() ...................................................................................................................... 401 El metodo include() ........................................................................................................................ 401 Obtener un objeto R e q ~ e s t D i s ~ a t c h ........................................................................................ er 401 Revision de Apoyo Tecnico ................................................................................................................ 401 La pigina techsupp.html ................................................................................................................ 402

..

TechSupportSe~let....................................................................................................................... 404 La pagina register.htm1 .................................................................................................................. 406 RegisterCustomerSe~let.............................................................................................................. 407 ResponseSe~let ............................................................................................................................. 408 BannerServlet ................................................................................................................................. 409 Configuracion de Apoyo Tkcnico y despliegue ........................................................................... 411 Utilizar RequestDispatcher para colaboraci6n ............................................................................ 412 Reenviar una solicitud a ResponseSemlet ...................................................................................... 412 Reenviar solicitud a regiter.htm1 ..................................................................................................... 412 Incluir insignia en ResponseSemlet ............................................................................................... 413 Resurnen ................................................................................................................................................. 413

Capitulo 8 Filtros para aplicaciones Web


i Q u i es u n filtro?

415
416

..................................................................................................................................... Filtro de rnuestra ..................................................................................................................................

418 Despliegue ....................................................................................................................................... 421

El API filtro .............................................................................................................................................. 422 La interfaz de filtro .............................................................................................................................. 422 El mktodo init () .............................................................................................................................. 423 El metodo doFilter() ....................................................................................................................... 423 El metodo destroy() ....................................................................................................................... 423 La interfaz Filterconfig ...................................................................................................................... 424 El metodo getFilterName() ............................................................................................................ 424 El mitodo getInitParameter0 ........................................................................................................ 424 El metodo getInitParameterNames() ............................................................................................ 424 El metodo getSemletContext() ...................................................................................................... 424 La interfaz Filterchain ........................................................................................................................ 424 El metodo doFilter() ....................................................................................................................... 425 Descriptor de despliegue para filtros ................................................................................................. 425 La aplicacidn de chat con filtros ............................................................................................................. 427 Registro de mensajes ........................................................................................................................... 428 Moderaci6n de mensajes ..................................................................................................................... 430 Descriptorde despliegue ...................................................................................................................... 434 Despliegue ....................................................................................................................................... 436 Chat con registro y moderaci6n ........................................................................................................ 437 Resurnen ..................................................................................................................................................... 438

Capitulo 9 Despliegue Web. autentificacion y empaquetado 4 4 1


Estructura de aplicacidn Web .................................................................................................................. 441 Estructura de directorio ...................................................................................................................... 442 Ficheros en archivo Web .......................................................................................................................... 444 Desplegar un archivo WAR .......................................................................................................... 445 i C u i n d o deben utilizarse 10s archivos WAR? ............................................................................ 446 Asociar de solicitudes a aplicaciones y servlets .................................................................................... 446

lndice
Asegurar aplicaciones Web ....................................................................................................................... 451 Seguridad programada .................................................................................................................. 454 El mitodo getAuthtype() ............................................................................................................... 454 El metodo getRemoteUser() ................................................................................................... 454 El metodo getUserPrincipal() .................................................................................................. 454 El mCtodo isUserRole() ................................................................................................................. 454 Autentificacibn basada en un formulario .................................................................................... 454 Configuraclon de despliegue 457 Parimetros de inicializaci6n de context0 .......................................................................................... 458 Parimetros de inicializaci6n de servlet ............................................................................................ 459 Cargar servlets en el arranque ............................................................................................................ 459 Tiempo limite de sesi6n ....................................................................................................................... 460 Asociaciones MIME ............................................................................................................................ 460 Archivos de bienvenida ....................................................................................................................... 461 Piginas de error ................................................................................................................................... 462 Enviar errores ............................................................................................................................ 463 Lanzar ServletException ......................................................................................................... 463 Manejar errores y excepciones HTTP ......................................................................................... 464 Aplicacionesdistribuibles .................................................................................................................... 465 Resumen .................................................................................................................................................... 468

..

...................................................................................................................

Capitulo 10 Fundamentos y arquitectura de JSP

471
471 472

........................................................................................................................ Presentaci6n de JSP ................................................................................................................................ Los aspectos pricticos .............................................................................................................................


La especificaci6n JSP 1.2

476 Directrices JSP ..................................................................................................................................... 477 La directriz page ............................................................................................................................. 477 Ejemplo ............................................................................................................................................ 479 La directriz include ......................................................................................................................... 479 Ejemplo ............................................................................................................................................ 480 La directriz taglib ...................................................................................................................... 482 Elementos de directivas ....................................................................................................................... 482 Declaraciones ................................................................................................................................. 483 Ejemplo ............................................................................................................................................ 483 Scriptlets ......................................................................................................................................... 484 Ejemplo ............................................................................................................................................ 484 Expresiones .................................................................................................................................... 486 Ejemplo ............................................................................................................................................ 487 Comentarios .................................................................................................................................. 487 Acciones estindar ................................................................................................................................ 488 <jsp:useBean> ............................................................................................................................... 488 <jsp:setProperty> ........................................................................................................................ 490 <jsp:getProperty> ..................................................................................................................492 <jsp:param> .................................................................................................................................. 495 <jsp:include> ................................................................................................................................. 495 <jsp:forward> .......................................................................................................................... 500 <jsp:plugin> .................................................................................................................................. 502 Objetos implicitos ............................................................................................................................... 505

lndice
El objeto Request ........................................................................................................................... 505 505 El objeto Response ........................................................................................................................ 505 El objeto Pagecontext .................................................................................................................. El objeto Session ........................................................................................................................... 505 506 El objeto Application ..................................................................................................................... 506 El objeto O u t ................................................................................................................................. 506 El objeto Config ............................................................................................................................ 506 El objeto Page ................................................................................................................................. Alcance .................................................................................................................................................. 506 507 Alcance de pigina ........................................................................................................................... 507 Alcance de solicitud ........................................................................................................................ 507 Alcance de sesi6n .......................................................................................................................... 507 Alcance de aplicacion ..................................................................................................................... 507 Piginas JSP como documentos XML ................................................................................................ 508 Directrices ...................................................................................................................................... 508 Elementos de directivas ................................................................................................................. Acciones ......................................................................................................................................... 509 509 Una pigina de ejemplo ................................................................................................................... 509 Sintaxis JSP ...................................................................................................................................... 509 Sintixis XML ................................................................................................................................... Apoyo tecnico JSP .................................................................................................................................... 509 511 Disefio de aplicacih ............................................................................................................................ 511 La pigina de bienvenida ....................................................................................................................... 512 La pagina JSP de procesamiento de solicitudes ............................................................................... 513 La clase JDBCHelper .......................................................................................................................... 514 TechSupportBean ................................................................................................................................. 516 Formulario de registro ........................................................................................................................ 517 JSP de registro ...................................................................................................................................... 517 Las piginas JSP de respuesta y de anuncio ......................................................................................... 518 La pigina de error ................................................................................................................................ 519 Desplegar la aplicacidn ......................................................................................................................... Estrategias de disefio JSP ......................................................................................................................... 520 521 Disefios centrados en la pigina o cliente-servidor ........................................................................... 521 Vista de pigina ...................................................................................................................................... 522 Vista de pigina con bean ..................................................................................................................... 523 El patron de controlador frontal ....................................................................................................... Implementaci6n de una arquitectura de controlador frontal .......................................................524 524 Servlet controlador ........................................................................................................................ 525 Manejadores de solicitud ............................................................................................................... 525 Beans de pigina .............................................................................................................................. 525 Vistas JSP ....................................................................................................................................... Implementation ............................................................................................................................. 526 534 Ventajas .......................................................................................................................................... 535 Utilizar un sistema de controlador genkrico ............................................................................... Resumen ................................................................................................................................................... 535

Capitulo 1 1 Extensiones de etiaueta de JSP


Extensiones de etiqueta ............................................................................................................................. 539

Mejoras de la extensi6n de etiqueta JSP 1.2 ....................................................................................... 542 Una sencilla etiqueta ................................................................................................................................. 542 Anatomia de una extensidn de etiquetas ................................................................................................ 546 Manejadores de etiqueta ....................................................................................................................... 547 La interfaz javax.se~let.jsp.tagext.Tag.............................................................................................. 547 ...................................................................... 550 La interfaz javax.se~let.js~.ta~ext.IterationTag La interfaz javax.se~let.jsp.tagextBodyTag ......................................................................... 550 La clase javax.servlet.jsp.tagextBodyContent .............................................................................. 552 Clases de conveniencia .................................................................................................................. 553 554 Objetos de disposici6n de 10s manejadores de etiqueta .............................................................. Revisi6n del sencillo ejemplo ........................................................................................................ 555 Descriptores de biblioteca de etiqueta ................................................................................................ 556 Utilizar extensiones de etiqueta en piginas JSP ................................................................................ 558 Despliegue y empaquetado de bibliotecas de etiquetas ....................................................................... 559 Asociaciones en Web.xm1 ............................................................................................................. 560 561 Paquete JAR de biblioteca de etiquetas ......................................................................................... Asociaci6n por defect0 .................................................................................................................. 561 Combinaciones de asociaci6n ....................................................................................................... 561 Escribir extensiones de etiqueta ............................................................................................................. 561 Atributos de procesamiento ................................................................................................................ 561 Contenido de cuerpo ........................................................................................................................... 565 Variables de directivas introducidas por etiquetas ............................................................................. 567 Cambios en el manejador de etiqueta ........................................................................................... 568 Ejemplo de variables de directiva .................................................................................................. 568 Definici6n programitica de variables de directiva ....................................................................... 571 573 Iteraci6n y manipulaci6n de contenido de cuerpo ............................................................................ 573 Evahaci6n repetida con la interfaz IterationTag ........................................................................ Etiquetas de cuerpo que filtran su contenido ............................................................................... 576 Anidamiento de etiqueta ...................................................................................................................... 578 Validar el uso de extensiones de etiqueta en piginas JSP .................................................................. 583 Manejo de errores ................................................................................................................................ 584 TryCatchFinally: ?un peligro para el disefio? .............................................................................. 590

................................................................................................... Locuciones de extensiones de etiqueta ................................................................................................... Resumen .....................................................................................................................................................


Eventos de ciclo de vida de aplicacidn

590 595 597

Capitulo 12 Escribir aplicaciones JSP con bibliotecas de etiquetas


Ventajas de utilizar bibliotecas de etiquetas personalizadas

599
600 601

............................................................... Ejemplos de bibliotecas de etiquetas existentes ..................................................................................... Introducci6n de la Biblioteca de Etiquetas Estindar JSP (JSPTL) ....................................................
Iniciarse en JSPTL

602 602 Obtener JSPTL .................................................................................................................................... <Qu6abarca JSPTL? ............................................................................................................................ 602

....................................................................................................................................

603

lndice
Integrar JSPTL en sus piginas JSP 604 U n ejemplo de iteraci6n ...................................................................................................................... 604 Ejecuci6n .............................................................................................................................................. 605 Etiquetas JSPTL .........................................................................................................................................
608

.........................................................................................................

Algunas consideraciones de disefio de JSPTL ...................................................................................... 609 Algunas etiquetas bisicas ..................................................................................................................... 609 Etiquetas de flujo de control ............................................................................................................... 610 Etiquetas de iteraci6n ....................................................................................................................612 Estado de iteraci6n ........................................................................................................................ 618 Capacidad de ampliaci6n de la etiqueta de iteraci6n ................................................................ 618 Etiquetas condicionales ....................................................................................................................... 619 Una aplicac~on de registro y autentificacion 622 La pigina de bienvenida .................................................................................................................. 623 El servlet controlador de registro ................................................................................................ 624 La pigina de formulario de registro .............................................................................................. 628 Etiquetas para el rnanejo de formularios HTML .................................................................. 632 Gracias por registrarse ........................................................................................................................ 636 Internacionalizaci6n de nuestro c6digo JSP ............................................................................... 637 i Q u e es un lote de recursos? ..................................................................................................... 637 C6mo se localizan 10s lotes de recursos ........................................................................................ 638 Aplicar lotes de recursos a aplicaciones JSP ..............................................................................639 La pigina de error de registro ............................................................................................................. 643 La pigina de formulario de entrada ................................................................................................644 Ver su perfil de usuario ......................................................................................................................645 Algunas ideas fundamentales sobre etiquetas en JSP ................................................................ 648 Pigina de error de entrada ............................................................................................................... 651 Ver el sitio Web favorito del usuario ................................................................................................. 652 Server-Side Includes (SSI) ............................................................................................................. 652 Algunos temas relacionados con Server-Side Includes ..............................................................653 Una etiqueta Server-Side Include .................................................................................................. 654 Administraci6n: la pigina Mostrar-todos-10s-usuarios .............................................................657 Administraci6n: un servicio Web de base XML ................................................................................659 Desplegar la aplicac~on de registro Lo que esti por Ilegar: la biblioteca de etiquetas estindar

..

.........................................................................................

..

.........................................................................................................

662 665 665

.................................................................................................................... Resumen .....................................................................................................................................................


Capitulo 13 JavaMail

Protocolos de correo 670 SMTP ....................................................................................................................................................670 POP3 ..................................................................................................................................................... 671 IMAP .................................................................................................................................................... 671 MIME ...............................................................................................................................................672 Andisis de JavaMail

................................................................................................................................

.................................................................................................................................

672

lndice

................................................................................................................. API de JavaMail .........................................................................................................................................


iRipido. enviarne u n e-mail!

674

675 javax.mail.Session ................................................................................................................................ 675 javax.mail.Authenticator ..................................................................................................................... 677 javax.mail.Message ............................................................................................................................... 678 javax.mai1.internet.MimeMessage ................................................................................................. 679 De ..................................................................................................................................................... 680 Para, C C y C C O ............................................................................................................................. 680 Responder a ..................................................................................................................................... 681 Asunto ............................................................................................................................................. 681 Fecha ................................................................................................................................................ 682 I D del mensaje ................................................................................................................................. 682 Otros ............................................................................................................................................... 682 javax.mail.Part ................................................................................................................................ 682 Sistema de activation de JavaBeans ................................................................................................ 683 javax.mail.Mu1tipart ......................................................................................................................... 685 javax.mail.BodyPart ......................................................................................................................... 686 Contenido del mensaje .................................................................................................................... 686 Indicadores de mensaje .................................................................................................................. 688 javax.mail.Address .........................................................................................................................689 javax.mail.internet.InternetAddress............................................................................................. 690 javax.mai1.internet.NewsAddress ................................................................................................. 691 javax.mail.Store .................................................................................................................................... 691 Acceso a las carpetas ......................................................................................................................692 javax.mail.URLName ..................................................................................................................... 694 javax.mail.Folder .................................................................................................................................. 695 Abrir y cerrar carpetas ................................................................................................................... 695 Mensajes de listado ........................................................................................................................ 696 Recuperacion avanzada de mensajes ............................................................................................... 697 Copiar y mover mensajes ........................................................................................................ 698 Buscar mensajes ............................................................................................................................. 699 Javax.mail.Transport ........................................................................................................................... 700

Trabajar con correo 701 Enviar correo ....................................................................................................................................... 701 Enviar documentos adjuntos ........................................................................................................ 703 Leer correo ........................................................................................................................................... 706 Eliminar correo .............................................................................................................................. 710 Recibir archivos adjuntos .............................................................................................................. 711 Guardar y cargar correo ...................................................................................................................... 712

...................................................................................................................................

..................................................................................................................................... Resumen .................................................................................................................................................


Recursos JavaMail

716 717

Capitulo 14 Arquitectura y dlseno EJB


i Q u 6 son 10s EJB? 720 Enterprise JavaBeans versus JavaBeans ........................................................................................ 721 Variedades de beans ........................................................................................................................722 iPor quO utilizar EJB? ......................................................................................................................... 723

....................................................................................................................................

El contenedor EJB y sus servicios .......................................................................................................... 724 725 Persistencia ..................................................................................................................................... 726 Transacciones declarativas ............................................................................................................ 726 Seguridad declarativa ...................................................................................................................... 726 Manejo de errores .......................................................................................................................... 726 Sistema de componentes para 16gica de empresa ......................................................................... 727 Reajustabilidad ................................................................................................................................ 727 Portabilidad ..................................................................................................................................... :.............................................................. 727 Gestionabilidad ................................................................ 727 C 6 m o proporciona servicios el contenedor ..................................................................................... 728 Contratos ....................................................................................................................................... 729 Servicios .......................................................................................................................................... 730 Interposici6n .................................................................................................................................. Trabajar con EJB ........................................................................................................................................ 731 732 La vista del desarrollador cliente ......................................................................................................... 734 La vista del proveedor de bean ............................................................................................................ 745 iQuC n o puede hacer un EJB? ............................................................................................................ 746 API responsable de 10s hilos ........................................................................................................ AWT ............................................................................................................................................... 747 747 Funcionar como un servidor de red ............................................................................................. Escribir en campos estlticos ......................................................................................................... 747 El paquete java.io ............................................................................................................................ 747 747 Cargar una biblioteca nativa .......................................................................................................... 748 Utilizar "this" como argument0 o valor de retorno ........................................................... 748 Retrollamadas ................................................................................................................................. Componentes EJB e n la Web ................................................................................................................... 748 Acceso de nivel cliente a EJB ................................................................................................................... 751 Diserio del nivel EJB ................................................................................................................................ 752 752 Ejemplos de uso de UML .................................................................................................................... 753 Objetos de anilisis ......................................................................................................................... 753 Objetos interfaz .............................................................................................................................. 753 Objetos control ............................................................................................................................... Objetos entidad ............................................................................................................................... 753 754 Anilisis versus implementaci6n ......................................................................................................... La funci6n de estado en el objeto interfaz ................................................................................... 756 U n ejemplo de disefio EJB .................................................................................................................. 757 Crear un product0 ......................................................................................................................... 759 759 Realizar un pedido .......................................................................................................................... 759 Cancelar un pedido ........................................................................................................................ 759 Seleccionar un pedido para su manufactura ................................................................................. 759 Elaborar un product0 .................................................................................................................... Enviar un pedido ............................................................................................................................ 759 760 Registrar pedidos atrasados ...........................................................................................................

fcapitulo 15 Beans de sesion y logica de empresa

Beans de seslon y estado ........................................................................................................................... 770

..

769

Representaci6n de 16gica de empresa .................................................................................................. 770 771 Beans de sesi6n como fachada ...................................................................................................... 773 El problema del estado conversacional .............................................................................................. Beans de sesion y almacenamiento persistente ................................................................................. 775 Bean calculadora de asistencia financiera ...............................................................................................776 Bean calculadora de necesidad financiera sin estado ......................................................................... 777 La interfaz rernota de calculadora de necesidad financiera .......................................................... 777 El cliente de necesidad financiera .................................................................................................. 777 La interfaz inicial calculadora de necesidad financiera ................................................................. 779 La clase de implementation de la calculadora de necesidad financiera ........................................ 779 780 public void ejbCreate0 .................................................................................................................... 781 public void ejbActivate0 ................................................................................................................. public void ejbPassivate() ................................................................................................................ 781 public void ejbRemove0 ................................................................................................................. 781 public void setSessionContext(SessionContext ctx) ....................................................................781 783 El descriptor de implementaci6n .................................................................................................. 784 Bean calculadores de necesidad financiera con estado ...................................................................... 784 La interfaz remota de necesidad financiera con estado .............................................................. La interfaz inicial calculadora de necesidad financiera con estado ............................................. 785 La clase de implementation de la siguiente calculadora financiera con estado ..........................785 789 El cliente para la calculadora de la necesidad financiera con estado ........................................... Descriptores de implementaci6n .................................................................................................. 789 792 Combinar beans con estado y sin estado .......................................................................................... Las nuevas interfaces y cliente de la calculadora de necesidad con estado .................................792 La nueva clase de implementaci6n de la calculadora de necesidad con estado ...........................792 795 Los descriptores de implementaci6n ............................................................................................ 796 Irnplementacion de nuestra aplicaci6n de fabricacion 798 Clientes e interfaces de logica de empresa .......................................................................................... El EJB Manageorders .................................................................................................................. 799 802 El EJB de fabricaci6n ..................................................................................................................... 803 Los clientes de aplicaci6n ............................................................................................................... El cliente BeginManufacture ........................................................................................................... 805 El cliente CompleteManufactured .................................................................................................. 806 El cliente PlaceSampleOrders ......................................................................................................... 808 809 El cliente ManagerSampleOrders ................................................................................................... 810 El cliente CreateProducts ................................................................................................................ Implementacidn del bean de sesi6n sin estado .................................................................................. 811 811 Mktodos de empresa ...................................................................................................................... 818 MCtodos de ayuda de irnplementaci6n .......................................................................................... MCtodos de ciclo de vida y de sistema .......................................................................................... 820 820 Irnplementaci6n del bean de sesi6n con estado ................................................................................. Resumen
L Capitulo

........................................................................

.....................................................................................................................................................
16 Beans de entidad y persistencia

826

829

i P o r quC n o utilizar beans de sesion? 830 830 Utilizar un bean de sesi6n con estado ................................................................................................ 833 Utilizar un bean de sesi6n sin estado ................................................................................................. Ventajas de 10s beans de entidad ......................................................................................................... 834

.....................................................................................................

Persistencia gestionada por contenedorversus persistencia gestionada p o r bean 835 Nuevas funciones para C M P introducidas en EJB 2.0 ..................................................................... 837 Accesores abstractos ..................................................................................................................... 838 Interfaces locales ............................................................................................................................ 839 Relaciones ....................................................................................................................................... 840 Lenguaje de consulta EJB .............................................................................................................. 840 La cllusula SELECT ........................................................................................................................ 841 La clausula FROM .......................................................................................................................... 841 La cliusula WHERE ........................................................................................................................ 842 laboratorio SportBean .................................................................................................................... 843 . . Claves primarlas ............................................................................................................................. 843 Las retrollamadas C.R.U.D. ................................................................................................................ 846 Crear ............................................................................................................................................... 846 Los me to do^ create() de Sports Team, interfaz inicial .................................................................. 846 La clase de implementaci6n de Sports Team CMP ........................................................................ 848 La clase de implementaci6n BMP de SportsTeam .......................................................................... 849 Leer .................................................................................................................................................. 851 Crear la tabla .................................................................................................................................... 851 Beans de entidad CMP y ejbLoad() ................................................................................................ 851 Beans de entidad BMP y ejbLoad() ................................................................................................ 852 Actualizar ........................................................................................................................................ 853 C M P y el metodo ejbStore() .......................................................................................................... 853 BMP y el metodo ejbStore() ........................................................................................................... 854 Eliminar .......................................................................................................................................... 854 C M P y el ~ n e t o d o remove() ........................................................................................................... 854 BMP y el d t o d o remove() ............................................................................................................ 855 Retrollamadas BMP versus retrollamadas C M P ..................................................................... 855 El descriptor de implementaci6n ........................................................................................................ 856 Persistencia en 10s descriptores de implementaci61-1................................................................ 857 Almacenamiento en memoria cache ................................................................................................... 858 Mitodos buscadores ............................................................................................................................ 861 Implementaci6n de metodos buscadores ..................................................................................... 861 C M P y metodos buscadores ........................................................................................................... 862 BMP y metodos buscador ............................................................................................................... 863 Activaci6n y pasivaci6n ....................................................................................................................... 864 El ciclo de vida completo ..................................................................................................................... 865 Reentrada .............................................................................................................................................. 866 Completar el ejemplo del equipo de deporte ...................................................................................... 867 El cliente C M P ................................................................................................................................. 868 El cliente BMP ................................................................................................................................. 869 Configurar WebLogic 6.1 para nuestros EJB ............................................................................. 872 Relaciones 873 Crear interfaces locales ........................................................................................................................ 873 Definir las relaciones ........................................................................................................................... 874 Completar nuestra aplicaci6n de fabricaci6n 875 El bean Pedido ...................................................................................................................................... 876 La interfaz inicial del bean Pedido ................................................................................................ 876 La interfaz remota del bean Pedido .......................................................................................... 877 La clase de implementaci6n del bean Pedido ............................................................................... 877

..........................

..................................................................................................................................................

........................................................................................

La clase de clave primaria del bean Pedido ...................................................................................... 880 La excepci6n OrderNotCancelableException ............................................................................... 881 El bean Producto .................................................................................................................................. 881 La interfaz inicial del bean Producto .............................................................................................. 882 La interfaz inicial local del bean Producto ...................................................................................... 882 La interfaz remota del bean Producto ............................................................................................ 883 La clase de implementaci6n del bean Producto .............................................................................. 883 La clase de excepcidn NoSuchRoutingInstruction ................................................................... 885 El descriptor de despliegue completo ................................................................................................. 885 Ejecutar la aplicacidn de fabrication ................................................................................................... 892 Resumen

.....................................................................................................................................................

894

Capitulo 1 7 Servicios de contenedor EJB

897

Transacciones 898 Transacciones sin contenedor ............................................................................................................ 900 Semintica declarativa para transacciones ........................................................................................... 907 El atributo rransaccional Notsupported ........................................................................................ 907 El atributo rransaccional RequiresNew .......................................................................................... 908 El atributo transaccional Required ................................................................................................. 908 El atributo transaccional Supports ................................................................................................. 908 El atributo transaccional Mandatory ............................................................................................. 908 El arributo transaccional Never ...................................................................................................... 908 Especificar atributos transaccionales ............................................................................................ 908 Elegir atributos de transaccion ..................................................................................................... 909 Transacciones controladas por el usuario ......................................................................................... 911 Niveles de aislamienro ......................................................................................................................... 913 Transacciones largas ............................................................................................................................ 915 Bloqueo optimista .......................................................................................................................... 916 Bloqueo pesimista .......................................................................................................................... 917 Realizaci6n en dos fases ...................................................................................................................... 917 Seguridad 917 Especificar 10s requisitos de seguridad ............................................................................................... 919 Roles de seguridad .......................................................................................................................... 919 Permisos de mitodo ...................................................................................................................... 921 Control programado de acceso .......................................................................................................... 922 Seguridad y disefio de aplicaci6n ......................................................................................................... 924 Excepciones 925 Excepciones de aplicaci6n .................................................................................................................... 926 Excepciones de aplicaci6n predefinidas ........................................................................................ 929 Excepciones de sistema ........................................................................................................................ 929 Comunicac~on 932 Comunicaci6n entre servidores heterogheos ............................................................................ 932 Llamadas de mitodo en VM ................................................................................................................ 934 Resumen

.............................................................................................................................................

...................................................................................................................................................

................................................................................................................................................

.. ..........................................................................................................................................

.....................................................................................................................................................

Capitulo 1 8 Roles de desarrollo y de implernentacion


El proveedor de bean de empresa

934

937
938

............................................................................................................

Indice

El ensamblador de la aplicacibn .............................................................................................................. 952

..................................................................................................................................... 963 El administrador del sistema .................................................................................................................. 973 Vendedor de contenedor/servidor de aplicacibn ................................................................................. 974 Una interfaz Web para la aplicaci6n de fabricacibn .............................................................................. 975 Consejos para resolver problemas ..........................................................................................................999 Resumen ................................................................................................................................................... 1000
El implementador

Capitulo 19 JMS y beans controlados nor mensaje


Breve historia del mensaje

................................................................................................................. Servicio de Mensajes Java (JMS) ...........................................................................................................

1004

1005 Punto-a-punto .................................................................................................................................... 1006 1007 Publicar/suscribir ............................................................................................................................... La arquitectura JMS ........................................................................................................................... 1008 Ejernplo de cola punto-a-punto ........................................................................................................ 1010 Producir un rnensaje .................................................................................................................... 1010 Consumir un rnensaje sincr6nicarnente .................................................................................... 1013 1015 Consurnir un rnensaje asincr6nicarnente ................................................................................... Ejernplo de apartado publicar/suscribir ............................................................................................ 1018

El API JMS .............................................................................................................................................. 1025 Utilizar transacciones con JMS ....................................................................................................... 1028 Tres irnplernentaciones JMS de peso industrial ............................................................................... 1029 SwiftMQ ....................................................................................................................................... 1029 1030 SpiritWave .................................................................................................................................... SonicMQ ...................................................................................................................................... 1030 Beans controlados por mensaje ............................................................................................................ 1031 Ciclo de vida del bean controlado por rnensaje ............................................................................... 1032 Transacciones en beans controlados por rnensaje .......................................................................... 1032 Transacciones gestionadas por bean .......................................................................................... 1033 Transacciones gestionadas por contenedor .............................................................................. 1033 1033 U n ejernplo de bean controlado por rnensaje .................................................................................. Irnplernentaci6n del bean controlado por rnensaje ......................................................................... 1034 Resumen ................................................................................................................................................... 1041

Capitulo 20 La arquitectura de conectores J2EE


Integraci6n de EIS y el rol de JCA

....................................................................................................... La Arquitectura de Conectores JZEE y sus elementos .......................................................................

1046

1048 Cornparaci6n de JCA con JDBC ............................................................................................... 1049 El adaptador de recursos y sus contratos ........................................................................................ 1050

Contratos de aplicaci6n ............................................................................................................... 1050 Contratos de nivel de sistema ..................................................................................................... 1051 1051 Gesti6n de conexiones .................................................................................................................. Gestion de transacciones .............................................................................................................. 1051 1052 Gesti6n de seguridad ..................................................................................................................... Acceso a EIS ................................................................................................................................ 1052 Empaquetado e implementacion de un adaptador de recursos ....................................................... 1053 1054 Empaquetar un adaptador de recursos .................................................................................. El descriptor de implementaci6n del adaptador de recursos (ra.xm1) ..................................... 1055 1058 Roles y responsabilidades de la implementacidn ....................................................................... Proveedor del adaptador de recursos ........................................................................................... 1058 1058 Vendedor del senidor de aplicacidn ............................................................................................. Proveedor del componente de aplicaci6n ..................................................................................... 1058 1059 Implementador .............................................................................................................................. 1059 Opciones de implementaci6n ..................................................................................................... Implementar un adaptador de recursos como una aplicacidn JZEE ........................................1059 1060 Adaptadores de recursos de caja negra Utilizar un adaptador de caja negra . El ejemplo Democonnector ............................................... 1060 ....., Seleccionar un adaptador de caja negra ...................................................................................... 1060 "-1 Transacciones XA y no-XA que utilizan un adaptador de caja negra ......................................... 1061 Implementation del adaptador de recursos de caja negra ......................................................... 1061 1061 Configurar la base de datos y la tabla Demoaccount ................................................................... Implementaci6n del adaptador de recursos .................................................................................. 1062 Poner a prueba el adaptador de recursos de caja negra ............................................................. 1067 1067 La interfaz inicial ........................................................................................................................... 1068 La interfaz remora ......................................................................................................................... La clase de implementaci6n del bean ............................................................................................. 1068 La clase ProcessingExceptions ..................................................................................................... 1073 El descriptor de implementacidn EJB .......................................................................................... 1073 1073 Implernentacion del bean .............................................................................................................. 1074 El cliente ......................................................................................................................................... La Interfaz C o m h de Cliente (CCI) .............................................................................................. 1076 Interfaces y clases C C I ................................................................................................................ 1076 1079 Conexi6n con una aplicaci6n gestionada (J2EE) ..................................................................... Conexi6n a una aplicacion no gestionada (de dos niveles) ...................................................... 1080 1082 Utilizar una C C I con adaptador de caja negra ................................................................................ 1082 Implementaci6n de un bean de sesi6n con C C I ....................................................................... 1083 La interfaz inicial ........................................................................................................................... La interfaz remora ......................................................................................................................... 1083 1083 La clase de implementaci6n del bean ............................................................................................. 1086 El descriptor de implementaci6n EJB .......................................................................................... 1087 El cliente ......................................................................................................................................... 1087 Implementacibn del adaptador de recursos de caja negra de C C I ........................................... Configurar la base de datos ........................................................................................................... 1088 1089 Implementaci6n del adaptador ...................................................................................................... 1091 Irnplementacion y prueba de la aplicaci6n C C I ......................................................................... Ventajas de la arquitectura de conectores J2EE 1092 1092 Integracidn de aplicacidn de empresa (EAI) con JCA ................................................................... 1092 Portales de empresa capacitados con J C A .......................................................................................

................................................................................................

...................................................................................

lndice
Integration empresa-a-empresa con JCA ........................................................................................ 1093

...........................................................................................................1093 Resumen ................................................................................................................................................... 1094


Elementos que faltan en J C A 1.0

'

Capitulo 2 1 Consideraciones de diseiio para aplicaciones J2EE


El m u n d o sigue cambiando

1097

...................................................................................................................1098 Arquitectura y disefio .......................................................................................................................... 1099

1099 Estilos de arquitectura ....................................................................................................................... Contexto de disefio ........................................................................................................................... 1101 1102 Los requisitos de empresa ................................................................................................................. 1102 El sistema existente .................................................................................................................... El sistema deseado ....................................................................................................................... 1103 1104 El context0 de empresa .....................................................................................................................

1105 Elaborar 10s requisitos Construir el modelo .......................................................................................................................... 1105 Exploration el modelo ...................................................................................................................... 1106 1106 Elaborar el context0 Adaptarse a1 terreno .......................................................................................................................... 1107 1107 Diseiio distribuido ............................................................................................................................. 1109 Elegir y perfeccionar una arquitectura Arquitectura para el sistema de pedidos de compra ......................................................................... 1109 1110 Iteraci6n y retroalimentacion ........................................................................................................... 1111 Aplicar patrones 1111 i Q u e son 10s patrones? ..................................................................................................................... 1112 Patrones J2EE .................................................................................................................................... Patron de controlador frontal .................................................................................................... 1114 1115 Patr6n de vista de composici6n .................................................................................................. Patron de fachada de sesion ........................................................................................................ 1117 1118 Patron de localizador de semicios ........................................................................................ Patron de Objeto valor ............................................................................................................... 1119 Patron de Delegado de empresa ............................................................................................1121 1122 Patron de Objeto de acceso a datos ............................................................................................ Patron de Ayudante de vista ........................................................................................................ 1123 1124 Patr6n de Vista de lanzador ........................................................................................................ Patr6n de Semicio a1 trabajador .................................................................................................. 1125 Patron de Manejador de lista de valores (Iterador pigina-a-pbgina) .......................................1125 Patr6n de Lector de via ripida ............................................................................................. 1127 1128 Comenzar por el principio 1128 Presentaci6n de datos del producto a1 usuario ................................................................................ Abstraer el acceso a datos .................................................................................................................. 1129 1130 Distinguir entre funcionalidad y presentacion ............................................................................. Separar interaction de usuario, presentaci6n y datos ..................................................................1131 1133 Evoluci6n del sistema ........................................................................................................................

...........................................................................................................................

................................................................................................................................

................................................................................................

.....................................................................................................................................

..................................................................................................................

Indice
Afiadir el nivel medio (Middle-Tier)

.................................................................................................. De compras ..............................................................................................................................................

1135

1137 Encapsular el flujo de trabajo de pedidos .....................................................................................1138 Modelos con estado versus modelos sin estado ....................................................................... 1139 Presentar el pedido ...................................................................................................................... 1141 Elegir un mecanismo asincrono ................................................................................................. 1141 Reajustabilidad disponibilidad a travks de la asincronicidad ...................................................1143 Cuestiones relacionadas con sistemas asincronos ...............................................................1143 Aprobar el pedido .............................................................................................................................. 1144

Mas all5 de sistema de pedidos de compra .......................................................................................... 1146 Disefio de interfaz EJB ..................................................................................................................... 1146 . . . Eventos d ~ s t r ~ b u ~ .......................................................................................................................... dos 1148 Disefio para bases de datos ................................................................................................................ 1148 Lecciones aprendidas .............................................................................................................................. 1149 Separar intereses siempre que sea posible ........................................................................................ 1149 Minimizar el trdfico de la red ............................................................................................................ 1149 Utilizar abstracci6n para contribuir a la flexibilidad ................................................................... 1150 Usar patrones comunes .................................................................................................................... 1150 Reducir el acoplamiento de mecanismos asincronos ...................................................................... 1151 Transacciones de plan ........................................................................................................................ 1151 Resumen ................................................................................................................................................... 1151

Capitulo 22 J2EE y servicios Web

1153

i Q u i son 10s servicios Web? ................................................................................................................. 1154 Servicios inteligentes ......................................................................................................................... 1155 Tecnologias de servicios Web ................................................................................................................ 1155

.................................................................................................................................................. 1155 Interoperabilidad .......................................................................................................................... 1157 Implementaciones ........................................................................................................................ 1157 Mensaies SOAP con anexos (SwA) ................................................................................................ 1157 . . WSDL ................................................................................................................................................. 1158 Documento WSDL ...................................................................................................................... 1158 El elemento types .......................................................................................................................... 1159
SOAP
El elemento message ..................................................................................................................... 1160 El elemento portType .................................................................................................................... 1160 El elemento binding ...................................................................................................................... 1160 El elemento port ............................................................................................................................ 1161 El elemento service ....................................................................................................................... 1161 U D D I ................................................................................................................................................. 1162 Implementation ........................................................................................................................... 1162

Tecnologias J2EE para servicios Web ................................................................................................... 1163 JAXP ................................................................................................................................................... 1164 JAXB ................................................................................................................................................... 1164 Esquema X M L .............................................................................................................................. 1164 Asociaci6n de datos X M L ........................................................................................................... 1165

JAXM .................................................................................................................................................. 1 166 TAX-RPC ............................................................................................................................................ 1168 JAXR ................................................................................................................................................... 1169 Arquitectura .................................................................................................................................. 1169 Objetivos de disefio ..................................................................................................................... 1170 Desarrollo de servicios Web .................................................................................................................. 1170 Arquitectura de servicio Web ............................................................................................................ 1171 Localizar servicios Web ............................................................................................................... 1171 La interfaz del servicio Web ........................................................................................................ 1172 Implementar la 16gica de empresa ............................................................................................... 1172 Integrar otros recursos ............................................................................................................... 1172 Devolver resultados a clientes .................................................................................................... 1172 U n sencillo servicio Web .................................................................................................................. 1173 Desarrollar el archivo Java StockQuote .................................................................................... 1173 Crear el JAR ................................................................................................................................. 1174 Generar archivos WSDL ............................................................................................................ 1174 El archivo StockQuote-Service.wsd1 ......................................................................................... 1177 El archivo StockQuote-Service-interface.wsd1 ......................................................................... 1177 Generar la clase proxy ................................................................................................................. 1179 Registrar el servicio en el servidor Web .................................................................................... 1179 Desarrollar un cliente .................................................................................................................. 1182 Crear servicios mas inteligentes .......................................................................................................... 1183 Contexto compartido ........................................................................................................................ 1183 Servicios Web inteligentes ................................................................................................................. 1184 La iniciativa Sun O N E ....................................................................................................................... 1184 Anilisis de la arquitectura funcional ........................................................................................... 1185 Arquitectura de servicios Web inteligentes ...................................................................................... 1186 Provisibn inteligente ................................................................................................................... 1187 Gesti6n inteligente ...................................................................................................................... 1187 Proceso inteligente ...................................................................................................................... 1187 Politica inteligente ........................................................................................................................ 1187 Apoyo del vendedor a servicios Web ................................................................................................... 1187 Servicios Web sencillos ............................................................................................................... 1187 Servicios Web complejos ............................................................................................................. 1188 Resumen

..................................................................................................................................................

1188

Capitulo 23 Elegir una implernentacion J2EE


Servidores de aplicaci6n

........................................................................................................................ Implementaci6n de las especificaciones J2EE ..................................................................................... Competencia en el mercado de servidores de aplicaci6n ................................................................

1191 1194

1196 Implementaciones J2EE .................................................................................................................... 1197 Funciones de valor afiadido ............................................................................................................... 1198 Implementation actual de normas futuras ................................................................................. 1200 Posibles caminos potenciales para funciones de valor afiadido ...............................................1201

indice

..................................................................................................................... Resumen ...................................................................................................................................................


Comunidad de desarrollo

1205 1206

Capitulo 24 Empaquetado e implernentacion J2EE

1209

Andisis del empaquetado J2EE ............................................................................................................ 1210 <QuC elementos pueden ser empaquetados? .................................................................................... 1210 Roles de empaquetado ........................................................................................................................ 1213 Las limitaciones del empaquetado ..................................................................................................... 1214 Comprender 10s esquemas de carga de clases .................................................................................. 1214 1215 La opci6n anterior a EJB 2.0 ...................................................................................................... La opcidn posterior a EJB 2.0 .................................................................................................... 1217 Una ambigiiedad en la especificacidn J2EE ................................................................................ 1218 Configuracidn de paquetes J2EE ........................................................................................................... 1218 El proceso de desarrollo de aplicaciones de empresa ...................................................................... 1218 1220 La estructura de un paquete J2EE ..................................................................................................... Trabajar con el descriptor de implementaci6n EAR ....................................................................... 1222 Ejemplo ......................................................................................................................................... 1223 Empaquetar 10s componentes ...................................................................................................... 1223 Ensamblaje de la apkaci6n ........................................................................................................... 1224 Implementaci6n de la aplicaci6n ................................................................................................... 1225 Ejecutar la aplicaci6n .............................................................................................................. 1225 Etiquetas opcionales de la etiqueta de implementaci6n ........................................................... 1226 Cuestiones relacionadas con el orden de 10s m6dulos ................................................................... 1227 Cuestiones relacionadas con paquetes de dependencia ...................................................................... 1227 Soluciones ........................................................................................................................................... 1228 Una soluci6n mejor ..................................................................................................................... 1229 1229 Comprender la ruta de clase manifiesta ..................................................................................... Ejemplo de dependencia ..................................................................................................................... 1230 El impact0 de las bibliotecas de dependencia .................................................................................... 1233 Resumen .............................................................................................................................................
1234

lndice alfabetico Soporte Tecnico de Anaya Multimedia

1237 1246

Introduccion
Bienvenido a la tercera edici6n de Programacidn para Java Server Profesional. A diferencia del cambio entre la primera y la segunda edici61-1, las diferencias de la versi6n 1.3 de J2EE son relativamente menores. Las diferencias fundamentales radican en que 10s capitulos sobre servlets, JSP y EJB han sido actualizados para reflejar 10s cambios realizados en las especificaciones relevantes, por ejemplo en EJB 2.0. Ademis, se han incluido nuevos capitulo para las nuevas caracteristicas de J2EE tales como la Arquitectura de Conectores y algunos capitulos menos relevantes para el desarrollo bisico de J2EE han sido eliminados.

La Gltima entrega de JRS-58, mis conocida como Plataforma Java 2, Enterprise Edition UZEE), representa la evoluci6n de la plataforma de desarrollo del lado del servidor de Sun Microsystems hacia una especificaci6n mis madura y sofisticada. Ademis de la inclusi6n de nuevas sub-especificaciones como JAAS (Java Authentication and Authorization Service) y la Arquitectura de Conectores, la verdadera naturaleza centrada en el contenedor de la especificaci6n de J2EE no ha sufrido cambios significativos. Los cambios mis notables de esta entrega estin relacionados con las modificaciones realizadas a las subespecificaciones, en especial a Servlet, JavaServer Pages (JSP) y Enterprise JavaBeans (EJB). Los servlets obtienen eventos y filtrado; JSP obtiene una nueva sintaxis XML y mejoras en 10s mecanismos de ajuste de designador; y EJB cuenta con algunos cambios significativos en su modelo de persistencia gestionado por su contenedor. Las versiones actuales de API en J2EE 1.3 se encuentran en:

O Servlets 2.3

lntroduccion
0 JavaServer Pages 1.2 0

Enterprise JavaBeans 2.0

O JDBC 2.0 Extension

O Java Message Service 1.0


0 Java Transaction API 1.0
O JavaMail 1.2 0 Java Activation Framework 1.0 0 Java API para XML Processing 1.1

O Java Conector Architecture 1.0


O Java Authentication and Authorization Service 1.0

A lo largo de este libro examinaremos todas estas versiones.

iQue ha cambiado en esta edicion del libro?


Observara que una parte del material de esta edici6n J2EE 1.3 es muy similar a1 contenido de su predecesora, la edici6n JZEE. Esto se debe a que antes de remendar notablemente el material esencialmente bueno y s6lido del libro, hemos decidido simplemente actualizar material relevante para seguir siendo consecuentes con las dltimas e~~ecificaciones identificadas por J2EE. En algunos casos, esto ha supuesto la inclusi6n de un capitulo adicional, per0 en otros s610 encontrari pequefios cambios. C o n todo ello, hay algunas diferencias significativas en lo que se refiere a capitulos entre esta edicion y la anterior. La edici6n J2EE 1.3 contiene capitulos sobre Arquitectura de Conectores Java, Servicios Web, c6mo elegir una implementacidn J2EE y Paquete de aplicaciones J2EE. Lo que ha sido eliminado son 10s capitulos mis ajenos que no eran esenciales para el aprendizaje sobre el desarrollo de aplicaciones J2EE, tales como la Internacionalizaci6n.

&A quien va dirigido este libro?


Este libro esti destinado a programadores profesionales de Java que, aunque no tengan mucha experiencia prictica, estin como minimo familiarizados con 10s conceptos fundamentales de programaci6n Web y de redes. Tambiin presupone estar familiarizado con el lenguaje Java y 10s API, a travis de la lectura de Beginning Java 2, o de algdn otro libro prictico que abarque un Area similar. Sin embargo, todos 10s conceptos relacionados con la programacion Java de lado servidor serin abordados sin presuponer conocimientos previos. N o obstante, se recomienda cierta familiaridad con las tecnologias bisicas Java de lado servidor, ya que este libro abarca una amplia area de conocimientos ripidamente y no pretende ser exhaustivo en todos 10s campos.

Ademis, 10s que ya posean la edicibn JZEE anterior del libro puede que encuentren que esta edicibn no les aporta muchos conocimientos ya que gran parte del material esencial es muy similar a la edici6n anterior.

lntroduccion

iCuales son 10s contenidos de este libro?


En este libro, examinamos tres temas principales:
0 Las normas de las especificaciones de tecnologia que deben seguir 10s creadores de programas para crear componentes de ernpresa.
0

Los limites y beneficios de las implementaciones tipicas reales de las compafiias distribuidoras de las especificaciones J2EE.

0 Los aspectos practicos resultantes de 10s disefios reales que utilizan las tecnologias J2EE.

El libro tiene la siguiente estructura basica:


0 Comenzaremos revisando las dtimas demandas planteadas a un agente de desarrollo de ernpresa de Java y analizando c6mo Java (y en particular J2EE) avanza para alcanzar estos retos. TambiCn tendri su primer contact0 con la arquitectura de contenedor J2EE.

DespuCs de que nos hayamos introducido a toda velocidad en la arquitectura J2EE, comenzaremos a analizar algunas de las tecnologias fundamentales en el desarrollo de una empresa: RMI, JDBC y JNDI.
0 Mis tarde, volveremos a J2EE de un modo mis explicito considerando c6mo desarrollar componentes Web utilizando 10s servlets de Java.

Una vez hayamos comprendido la tecnologia de servlets, estudiaremos c6mo se incorpora a JavaServer Pages y se amplia para proporcionar un medio mas flexible para crear contenido Web dinimico.
0

Finalmente, analizaremos algunas temas extensos de J2EE tales como consideraciones de disefio y c6mo crear paquetes con sus aplicaciones J2EE.

Lo necesario para utilizar este libro


La mayor parte del codigo de este libro ha sido probado con la Plataforma Java 2, Standard Edition SDK (JDK 1.3) y la Plataforma Java 2, Enterprise Edition SDK 1.3 Implementaci6n de Referencia. Sin embargo, para algunos capitulos, bien la implementaci6n de referencia no es suficiente o necesita software adicional:

Contenedor Web
Para ejecutar 10s componentes Web utilizados en este libro, necesitari un contenedor Web que soporte las especificaciones Servlet 2.3 y JSP 1.2. Nosotros utilizamos la Implementaci6n de Referencia, que utiliza el motor Jakarta Tomcat bajo la cobertura. Puede que necesite la ~iltima versi6n de Tomcat (disponible en http:/ /jakarta.apache.org/tomcat) para poder ejecutar algunas 10s ejemplos de las librerias de designador JSP.

Contenedor EJB
Para 10s capitulos EJB, tambikn necesitari un contenedor EJB que mantenga la versi6n 2.0 de la especificaci6n EJB. Nosotros utilizamos WebLogic Server 6.1 de BEA (http://www.bea.com).

Bases de datos
Varios capitulos requieren tambikn acceso a una base de datos. Para estos capitulos, nosotros utilizamos: Cloudscape (una versi6n interna viene con el RI de J2EE), http://cloudscape.com/

Introduccion

Software adicional
Finalrnente, un par de capitulos tarnbitn requieren algunas piezas de software adicional:
O J N D I SDK de Sun, que esti incluido en JDK 1.3 O Java Secure Sockets Extensi6n USSE) 1.0.1, http://java.sun.com/products/jsse/ O Servidor LDPA (iPlanet Directory Server version 4.11 de Netscape), http://w.iplanet.com/ O Servicio SMTP y/o POP3 O JSP Standar Tag Library, http://jakarta.apache.orgltaglibs

U Web Services Toolkit de IBM, http://w.alphaworks.ibm.com/tech/webservicestoolkit

El cbdigo del libro funcionari en un ordenador sencillo, siernpre que est6 en red (es decir, que pueda ver http://localhost a trav6s del navegador local). El c6digo fuente cornpleto del libro esti disponible para su desacarga en: http://w.wrox.com/
http://w.AnayaMultimedia.es (seccion "atencion a1 cliente", opcion "complementos")

Convenciones
Para ayudarle a sacar el mixirno partido a1 texto y seguir el hilo de lo que esti ocurriendo, hernos utilizado un nGrnero de convenciones a lo largo del libro: Por ejernplo:

Estos recuadros contienen inforrnaci6n irnportante que debe recodar y que es relevante con relaci6n a1 texto en el que se introduce. Mientras que el estilo en cursiva se utiliza para comentarios a1 margen del tema que esta' siendo tratado.
En cuanto a 10s estilos en el texto:
O A1 introducirlas,

destacarnos en negrita las palabras irnportantes. Control-A

O Mostrarnos las cornbinaciones de teclado asi:

O Mostrarnos 10s nornbres de 10s archivos y c6digos en el texto asi: d o G e t ( ) O

El texto sobre interfaces de usuario y URL se rnuestran corno: Menu

Presentarnos el cbdigo de tres forrnas diferentes. Las definiciones de rnttodos y propiedades se rnuestran del siguiente rnodo:
protected void doGet(HttpServ1etRequest req, HttpServletResponse resp) throws ServletException, IOException

Ejernplo de un c6digo:
Eri r , u e s t r o s ejernplos rnuestra e l c 6 d i g o de cbdigos, e l . e s t i l o de primer nuevrj, i r n p o r t a n t e y p e r t i n e n t e p l a r ~ ode c6digo

lntroduccion
M i e r ~ t r a s q u e e l f o n d o d e c b d i g o m u e s t r a e l c 6 d i g o menos i m p o r t a n t e c o n t e x t o o i n d i c a q u e ;/a ha s i d o m o s t r a d o c o n a n t e r i o r i d a d . en su

Atencion al cliente
Siempre valoramos recibir noticias de nuestros lectores y queremos saber quk piensa sobre este libro: lo que le ha gustado, lo que no le ha gustado y lo que considera que podemos mejorar en la pr6xima edici6n. Puede enviarnos sus comentarios, bien rnediante la tarjeta de respuesta incluida a1 final del libro o por email a e e d b a c k e w r o x . corn o a-rnultirnediaeanaya. e s . Asegirese de que inchyeel titulo del libro en su mensaje.

Como cargar el codigo de muestra para el libro


Cuando visite la pigina de Wrox, http://wrox.com/,simplemente localice el titulo en nuestra seccicin s e a r c h o utilice uno de 10s titulos de la h a . Haga clic en Download en la columna Code o en Download Code en la pigina de detalles del libro. Tambikn podri descargar el codigo en la pigina de Anaya Multimedia, http:// www.AnayaMultirnedia.es (seccion "atencMn a 1 cliente", opcion "complementos") Los archivos disponibles para su descarga en nuestra pigina han sido archivados utilizando el programa WinZip. Cuando haya guardado 10s archivos adjuntos en una carpeta de su disco duro, necesitari extraer 10s archivos utilizando un programa de descompresi6n como WinZip o PKUnzip. Cuando extraiga 10s archivos, el c6digo se extraeri normalmente en carpetas de capitulos. Cuando inicie el proceso de extracci61-1, asegjrese de que su programa (WinZip, PKUnzip, etc.) esti configurado para utilizar 10s nombres de las carpetas.

Erratas
Nos hemos esforzado al miximo para que no haya errores en el texto o en el c6digo. Sin embargo, nadie es perfecto y puede haber errores. Si encuentra a l g h error en alguno de nuestros libros, como un error de ortografia o un segment0 de ccidigo err6ne0, le agradeceriamos que nos lo hiciera saber. Informindonos de las erratas, ahorrari a otro lector horas de frustracicin y, por supuesto, nos estari ayudando a ofrecer informacidn de mayor calidad. Simplemente, envienos un e-mail con la informaci6n a s u p p o r t @ w r o x .corn o a-mu1 t i m e d i a e a n a y a .e s ; su informaci6n seri comprobada y, si es correcta, seri enviada a la pigina de erratas del libro en cuesti6n o utilizada en siguientes ediciones del libro. , Para encontrar erratas en la pigina Web, vaya a http://www.wrox.corny simplemente localice el titulo en nuestro apartado d e l ~ d v a n c e dS e a r c h o en la h a de titulos. Haga clic en el vinculo Book E r r a t a , que se encuentra bajo la cubierta grifica de lapigina de detalle del libro. Tambikn podri encontrar las erratas en la pigina Web http://www.AnayaMultirnedia.es (seccion "atencidn a 1 cliente", opcion "complementeos").

Apoyo via e-mail


Si desea plantear directamente un problema del libro a un experto que conozca el libro detalladamente, envie un e-mail a a - a n a y a m u l t i r n e d i a e a n a y a . e s o a s u p p o r t @ w r o x . corn (incluyendo el titulo del libro y 10s cuatro iltimos nimeros del ISBN en inglks en el campo de asunto del e-mail). U n e-mail convencional incluiria 10s siguientes datos:
0 El titulo del libro, 10s cuatro ultimos digitos del ISBN en inglis, un numero de pigina donde se encuentra el problema en el campo A s u n t o .

lntroduccion
o Su nombre, 10s datos de contacto y el problema en el cuerpo del rnensaje.
N o le enviaremos ningfin correo basura. Necesitarnos 10s detalles para ahorrarle tiernpo a usted y a nosotros. Cuando envie un e-mail, kste pasari por la siguiente cadena de atenci6n:
0

Apoyo el cliente. Su rnensaje es enviado a nuestro personal de atenci6n a1 cliente, que serin 10s prirneros en leerlo. Ellos cuentan con archivos sobre las preguntas mis frecuentes y responderin a cualquier pregunta general sobre el libro o sobre la pigina Web inrnediatarnente. Editorial. Las preguntas de mayor profundidad son enviadas a1 equipo editor tkcnico responsable del libro en cuesti6n. Ellos tienen experiencia con el lenguaje de programaci6n o con el product0 en cuestion y estin capacitados para responder a preguntas tkcnicas sobre el terna. Autores. Finalrnente, en el improbable caso de que el editor no pueda resolver su problema, enviari la pregunta a1 autor. Intentamos proteger a1 autor de cualquier distracci6n en su trabajo; sin embargo, nos satisface poder plantearles problemas especificos. Ellos enviarin un e-mail a1 cliente y a1 editor con su respuesta y una vez rnis todos 10s lectores se beneficiarin.

El proceso de Apoyo de Wrox solo puede ofrecer apoyo sobre ternas que estin directarnente relacionados con nuestros titulos publicados. La respuesta a las preguntas que estin fuera del irnbito normal del apoyo a nuestros libros puede encontrarla en las listas cornunitarias de nuestro for0 en http://p2p.wrox.cotW.

Para participar en debates con el autor y otras personas, registrese en las listas de correo de P2P. Nuestro sisterna dnico proporciona contacto programmer-to-programmer'" en las listas de correo, en 10s foros y en 10s grupos de noticias, todo ello surnado al sisterna individual de apoyo via e-mail. Si envia sus dudas a P2P, puede estar seguro de que serin examinados por rnuchos de 10s autores de Wrox y otros expertos de la industria que estin incluidos en nuestras listas de correo. En p 2 p . w r o x .comencontrari diversas listas diferentes que le ayudarin no s61o en la lectura de este libro, sin0 tambikn a desarrollar sus propias aplicaciones. Para este libro, son especialrnente apropiadas las listas j2ee y projava-server. Para suscribirse a una lista de correo, debe seguir 10s siguientes pasos:
0 0

Vaya a http://p2p.wrox.cotW Elija la categoria apropiada de la barra de rnenfi situada a la izquierda

m Haga clic en la lista de correo a la que desea suscribirse


Siga las instrucciones para suscribirse y rellene 10s carnpos de su direcci6n de e-mail y su contrasefia

m Conteste a1 e-mail de confirrnaci6n que reciba


o Utilice el gestor de suscripciones para suscribirse a rnis listas y fije sus preferencia de correo

lPor que este sistema ofrece el mejor apoyo?


Puede elegir entre suscribirse a las listas de correo o puede recibirlas sernanalmente. Si no tiene tiernpo, o rnedios, para recibir las listas de correo, puede buscar en nuestros archivos on-line. Los correos basura y rnolestos son borrados autorniticarnente, y su direccion de correo esti protegida por el sisterna finico Lyris. Las preguntas sobre c6rno suscribirse o darse de baja en las listas, y para cualquier otra duda general sobre las listas, envie un rnensaje a l i s t s u p p o r t @ p ~ w p .r o x . corn

.-

Java

Server --

CORBA
1

Plataforma JZEE
En la actualidad, Java es uno de 10s lenguajes de programacion mis elaborados y mis utilizados para la creaci6n de software de empresa. La evoluci6n de Java, que ha pasado de ser un medio de desarrollo de applets para ser ejecutados en navegadores a un modelo de programacibn capaz de manejar las aplicaciones de una empresa de hoy en dia, ha sido extraordinaria. Con el paso de 10s afios, Java ha desarrollado tres ediciones de plataformas diferentes, cada una de ellas destinada a cubrir un conjunto diferente de necesidades de programacibn:
O

La plataforma Java 2 Standar Edition U2SE): Es la plataforma mis utilizada dentro de Java, consistente en un entorno de tiempo de ejecucibn y un conjunto de varios API para crear una amplia variedad de aplicaciones que abarca desde applets, pasando por aplicaciones independientes ejecutables en distintas plataformas, hasta aplicaciones de cliente para diversas aplicaciones de empresa. La plataforma Java 2, Enterprise Edition (J2EE): J2EE es una plataforma para crear aplicaciones de senidor. Como veri a lo largo de este libro, las aplicaciones de servidor tienen requisitos adicionales durante la fase de desarrollo. J2EE proporciona la infraestructura necesaria para satisfacer estas necesidades. La plataforma Java 2, Micro Edition (J2ME): Esta edicibn, la ultima en agregarse a la familia Java, permite la creaci6n de aplicaciones Java para "micro-dispositivos" (dispositivos con un apoyo de pantalla y memoria limitado, como telkfonos moviles, PDAs, etc.).

Este libro es un recorrido por la plataforma J2EE y, en particular, por la version 1.3 de la especificacion. Ya que J2EE 1.3 requiere J2SE, tambikn examinaremos algunas de las caracteristicas de J2SE cuando asi se requiera. En este libro, comenzaremos presentando las necesidades de programacibn para el desarrollo de aplicaciones de empresa, las diversas tecnologias disponibles para la creacibn de tales aplicaciones y el

Capitulo 1
mod0 de crear tales aplicaciones utilizando esas tecnologias. A medida que vayamos avanzando capitulo a capitulo, nos encontraremos con una amplia variedad de tecnologias, algunas de ellas de mayor complejidad y cada una de ellas abarcando un grupo especifico de necesidades tkcnicas. Este libro le presentari pricticamente toda la gama de tecnologias J2EE. A pesar de la complejidad de algunas de estas ireas, este libro pretende presentar cada uno de 10s temas desde 10s principios rnis bisicos. De este modo, el lector puede estudiar estos temas en el orden que prefiera.

Programacion para empresas


J2EE lleva cuatro afios de funcionamiento. Durante estos afios, ha reemplazado a diversas tecnologias de propiedad y no estindar como opci6n id6nea para e-comercio y otras aplicaciones de empresa de base Web. Considerando la multitud y la complejidad de 10s requisitos de infraestructura tkcnica para las aplicaciones de e-comercio, en este capitulo conoceri c6mo J2EE se adapta a estos requisitos proporcionando una infraestructura exhaustiva. H o y en dia, J2EE es una de las dos opciones disponibles para la creaci6n de aplicaciones de e-comercio. La otra opci6n la encontramos en Windows de Microsoft y en las tecnologias . NET. Desde sus comienzos, Java ha dado lugar a la creaci6n de nuevos modelos y tecnologias de programaci6n en diferentes campos, desde 10s dispositivos rnis sencillos hasta aplicaciones de empresa, pasando por telefonia. A1 mismo tiempo, Java ha funcionado como catalizador a la hora de conseguir que ciertos campos de la tecnologia adopten formas rnis seguras y sblidas. La plataforma de informitica de empresa de Java, la Plataforma Java 2, Enterprise Edition (JZEE), es uno de estos campos. En el pasado, 10s debates en 10s medios de comunicaci6n, asi como en 10s circulos tkcnicos, han cuestionado si Java es un lenguaje de programaci6n o una plataforma sobre la que construir y presentar aplicaciones. J2EE es, de hecho, uno de 10s intentos rnis efectivos por parte de Sun y sus asociados en hacer que Java resulte creible comoplataforma para informitica de empresa distribuida. iPor quk J2EE? iPor quk es la plataforma adecuada? (Por quk deberia elegir esta tecnologia para crear aplicaciones en el imbito empresarial, desde cliente-servidor a Internet hasta m6viles? Este capitulo le ofrece una visi6n equilibrada de J2EE y le ayuda a encontrar respuestas a estas preguntas. El resto de este libro es un anilisis rnis profundo de las tecnologias individuales y demuestra c6mo construir y gestionar con kxito tales aplicaciones de empresa. En este capitulo introductorio centraremos nuestra atenci6n en 10s siguientes puntos:
0

La arquitectura tkcnica de J2EE. Las caracteristicas que hacen de J2EE una plataforma creible.

a
0

U Los retos a 10s que se enfrenta J2EE.

Las tecnologias que comprende la plataforma J2EE.

En primer lugar, n o obstante, empezaremos con el reto que supone hoy en dia para las empresas el desarrollo de aplicaciones.

La empresa actual
Este libro aborda la creaci6n de aplicaciones de empresa, per0 ia quk nos referimos exactamente cuando hablamos de una "empresa"?

46

Plataforma J2EE
U n a ernpresa es una organizaci6n econ6rnica y las aplicaciones de ernpresa son aquellas aplicaciones de software que facilitan diversas actividades dentro de una ernpresa. Las aplicaciones de ernpresa pueden ser aquellas que hacen concesiones a 10s usuarios finales via Internet, a colaboradores via Internet o redes privadas, a diversas unidades econ6micas dentro de la ernpresa via distintos tipos de interfaces de usuario, etc. En esencia, las aplicaciones de empresa son aquillas que perrniten a una ernpresa gestionar sus actividades econ6rnicas. Ejernplos de tales actividades inchyen planificaci6n de recursos, inventarios y catilogos de productos, preparaci6n de facturas, satisfaccidn de bienes y servicios prestados, etc. Crear aplicaciones para una ernpresa siempre ha sido un reto. Algunos de 10s factores que contribuyen a este reto y su cornplejidad son 10s siguientes:
CI Diversidad de necesidades de inforrnaci6n

En una ernpresa, la inforrnacion es creada y consurnida por varios usuarios en una serie de forrnas diferentes, dependiendo de necesidades especificas. Es rnuy cornun encontrar que cada actividad econdmica procesa la inforrnaci6n de un rnodo diferente.
D Cornplejidad de procesos econ6rnicos

La mayoria de procesos econ6rnicos de ernpresa conllevan recabar inforrnaci6n compleja, procesarla y distribuirla. C o n rnucha frecuencia, se enfrentari a una 16gica cornpleja para recabar y procesar inforrnaci6n. Esto tiene corno resultado unos complejos requisitos ticnicos y de arquitectura para crear aplicaciones de ernpresa.
CI Diversidad de aplicaciones

Debido a la compleja naturaleza de 10s procesos econ6rnicos de empresa, es frecuente encontrar una ernpresa consistente en un gran nurnero de aplicaciones, cada una de ellas creada en distintos mornentos para satisfacer las necesidades de distintos procesos econ6rnicos. Esto desernboca con frecuencia en la presencia de aplicaciones creadas utilizando diferentes arquitecturas y tecnologias. U n o de 10s retos a 10s que se enfrentan las ernpresas hoy en dia es la necesidad de conseguir que dichas aplicaciones se cornuniquen entre si de rnodo que 10s procesos econ6micos puedan llevarse a cab0 sin interrupciones. Estos factores son rnuy comunes y las ernpresas incurren en enormes costes para crear y gestionar aplicaciones que hagan frente a estos retos. Durante 10s filtirnos ahos, estos retos han alcanzado dirnensiones rnonstruosas. Gracias a Internet y a1 reciente crecirniento del e-cornercio, 10s dispositivos de inforrnaci6n de una ernpresa son ahora mis valiosos. Este carnbio hacia una econornia de la informacion e s t i forzando a rnuchas cornpahias a reforrnular incluso sus pricticas economicas rnis bisicas. C o n el objetivo de rnantener un rnargen cornpetitivo, la adopci6n de nuevas tecnologias para cubrir las necesidades del rnornento ripidarnente se ha convertido en un factor clave en la habilidad de una ernpresa para explotar a1 rnixirno sus dispositivos de inforrnacion. Fundarnentalrnente, la adaptation de estas nuevas tecnologias para que funcionen en cornbinacibn con 10s sistemas legados ya existentes es ahora uno de 10s requisitos principales de la empresa. Uno de 10s lugares donde estos cambios se han percibido de un rnodo mis intenso ha sido en el imbito del desarrollo de aplicaciones. A lo largo de 10s ultirnos ahos, 10s fondos y el tiernpo invertidos en el desarrollo de aplicaciones se han visto reducidos, rnientras que las dernandas para crear cornplejos procesos econ6rnicos han aurnentado. Sin embargo, arnbos son obsticulos que 10s prornotores pueden superar, per0 tarnbiin se encuentran con 10s siguientes requisitos que cumplir:
0 Productividad de prograrnaci6n

La adopci6n directa de nuevas tecnologias es insuficiente si istas no son utilizadas adecuadamente aprovechando su potencial a1 mixirno y si no son integradas apropiadarnente con otras tecnologias

Capitulo 1
relevantes. De este modo, la habilidad para desarrollar y despuks desplegar las aplicaciones tan ripida y efectivamente como sea posible es muy importante. Conseguir este objetivo puede resultar complicado debido a la gran variedad de tecnologias y normas que han sido desarrolladas a lo largo de 10s afios, que requieren capacidades altamente desarrolladas; tan s61o adquirirlas y mantenerse a la altura es un problema en si mismo. Ademis, el ripido ritmo de cambio en las mismas normas dificulta la tarea de asegurar un eficiente engranaje de las tecnologias.
0

Fiabilidad y disponibilidad En la economia actual de Internet, el tiempo de inactividad puede resultar fatal para una empresa. La habilidad para organizar y poner en marcha sus operaciones de base Web, y mantenerlas activas, es crucial para lograr el objetivo con kxito. Y por si no fuera suficiente, t a m b i h debe ser capaz de garantizar la fiabilidad de sus transacciones econ6micas de mod0 que Sean procesadas por completo y con exactitud. Seguridad Internet no s61o ha aumentado exponencialmente el numero de usuarios potenciales sino tambikn el valor de la informaci6n de una compafiia, de mod0 que la seguridad de esta informaci6n se ha convertido en una preocupaci6n de primer orden. Es mis, a medida que las tecnologias son mis avanzadas, las aplicaciones mis sofisticadas y las empresas mis complejas, poner en marcha un modelo de seguridad efectivo es cada vez mis dificil. Reajustabilidad La capacidad de una apkaci6n para crecer y ajustarse a una nueva demanda, tanto en su operacidn como en su base de usuario, es esencial. Esta condici6n se cumple especialmente cuando consideramos que la base potencial de usuarios de una aplicaci6n puede ser de millones de usuarios individuales, via Internet. La capacidad efectiva de reajuste depende no s61o de la habilidad para manejar un amplio aumento en el numero de clientes sino tambikn del uso efectivo de 10s recursos de un sistema.

Integraci6n Aunque la information ha crecido hasta convertirse en un dispositivo econ6mico clave, mucha de esta informaci6n existe como datos en sistemas de informacibn viejos y obsoletos. Para maximizar la utilidad de esta informaci6n, las aplicaciones deben poder ser inteqadas en 10s sistemas de informaci6n ya existentes, lo cual no es necesariamente una tarea ficil ya que las tecnologias actuales con frecuencia han avanzado hasta superar algunos de estos sistemas legados. La habilidad para combinar las nuevas y las viejas tecnologias es fundamental para el kxito del desarrollo de las empresas de hoy en dia.

iEstamos buscando f6rmulas migicas para enfrentarnos a estos desafios? A pesar de las promesas de evangelistas y vendedores, n o es aconsejable esperar (o confiar en) una soluci6n que evite o supere por completo estos retos. Lo que las empresas estin buscando es una tecnologia y una infraestructura permisiva que simplifique algunos de 10s temas tkcnicos complejos. A medida que vaya avanzando en este libro, encontrari el anilisis de estos temas. Ninguno de estos imbitos problemiticos es especialmente nuevo para 10s creadores de programas de una empresa. Pero resolverlos de un mod0 exhaustivo y rentable sigue siendo crucial. Puede que sea consciente de que han existido diversas tecnologias para resolver una o mis de las demandas anteriores. Sin embargo, lo que siempre ha faltado ha sido una plataforma con una rica infraestructura y numerosas posibilidades de arquitectura que promueva a1 mismo tiempo un ripido entorno de desarrollo. El objetivo de JZEE es simplificar algunas de las complejidades tkcnicas y especificar 10s siguientes puntos para crear aplicaciones de empresa:
0

U n modelo de programaci6n, consistente en un conjunto de interfaces de programaci6n de aplicaciones (API) y e n 10s enfoques para la creaci6n de dichas aplicaciones.

Plataforma J2EE
Una infraestructura de aplicaci6n, para respaldar las aplicaciones de empresa creadas utilizando 10s API.

1Es Java la respuesta?


Hasta ahora hemos examinado nuestra arquitectura de sistema desde una perspectiva agnostics en cuanto a su ejecuci6n. De hecho, existen muchos caminos potenciales que pueden tomarse para poner en marcha su empresa. Existen esencialmente dos caminos principales: uno emprendido por Microsoft, con su nueva iniciativa. NET, y el segundo, emprendido por Sun y otras empresas tales como BEA, IBM, Oracle, etc. Teniendo en cuenta las opciones, ipor quC deberia ser Java una excelente elecci6n? Examinemos algunas de sus ventaias.

lndependiente de la plataforma
Con la informacion de una empresa desplegada en formatos dispares, en distintas plataformas y aplicaciones, es importante adoptar un lenguaje de programacion que pueda funcionar perfectamente en la empresa sin tener que recurrir a mecanismos extrafios e ineficientes de traduccion. U n modelo de programacion unificador tambikn reduce las dificultades surgidas de la integration de muchas de las diversas tecnologias que se convierten en especificas para ciertas plataformas y aplicaciones.

Objetos gestionados
J2EE proporciona un entorno gestionado para componentes y las aplicaciones de J2EE son centricas respecto del contenedor. Ambas nociones son criticas para construir aplicaciones de cliente. A1 ser ges;ionados, 10s componentes de J2EE utilizan la infraestructura prop&cionada por 10s servidores de J2EE sin que el programador sea consciente de ello. Las aplicaciones de J2EE son tambiCn declarativas, un mecanismo con el que puede modificar y controlar el funcionamiento de las aplicaciones sin cambiar de codigo. A primera vista, estas caracteristicas pueden parecer incomodas de ejecutar. Sin embargo, cuando considera las aplicaciones a gran escala con varios cientos de componentes interactuando para ejecutar complejos procesos empresariales, estas caracteristicas hacen que crear y mantener tales aplicaciones resulte menos complejo. Junto con su independencia respecto de la plataforma, iste es uno de 10s aspectos mis importantes de JZEE.

Reusabilidad
La reutihaci6n del c6digo es el Santo Grial de la programacion. Separar 10s requisitos econ6micos de una aplicacion en sus partes integrantes es un modo de conseguir la reutilizacibn; utilizar la orientation a1 objeto para encapsular la funcionalidad compartida es otro. Sin embargo, a diferencia de 10s objetos, 10s componentes distribuidos requieren una infraestructura mis compleja para su construccidn y gesti6n. Los conceptos bisicos orientados a objetos no proporcionan este tip0 de marco, pero la Enterprise Edition de Java ofrece una arquitectura notablemente rigurosa para la reutilizacion de componentes. Los componentes de empresa (Ilamados Enterprise JavaBeans) desarrollados en J2EE son de basica granulometria (aunque la especificacion EJB 2.0 en J2EE 1.3 permite un enfoque de granulometria mis fina) y reproducibles. Manteniendo estos componentes bisicos, es posible crear funcionalidades de empresa complejas de un modo libremente coordinado. Ademis, ya que 10s componentes son reproducibles, lo cual quiere decir que es posible identificar ciertos metadatos sobre 10s componentes, las aplicaciones pueden ser creadas componiendo tales componentes. Ambas caracteristicas fomentan la reutilizaci6n del c6digo a alta granulometria.

Capitulo 1 Modularidad
A la hora de desarrollar una aplicacidn de servidor completa, 10s programas pueden ampliarse y complicarse ripidamente. Siempre es mejor romper una aplicacidn en m6dulos discretos, cada uno de ellos responsable de una tarea especifica. Esto hace que nuestras aplicaciones sean mucho mis ficiles de mantener y comprender. Por ejemplo, 10s servlets de Java, las Piginas de JavaServer y Enterprise JavaBeans proporcionan un modo de modularizar nuestra aplicaci6n, rompiendo nuestras aplicaciones en diferentes niveles y tareas individuales. A pesar de las caracteristicas a su favor mencionadas, Java no present6 un modelo de programaci6n unificador a escala de empresa hasta principios del afio 2000. N o es que no tuviera la capacidad, sino que en el pasado estaba algo desorganizada. Sun reconoci6 este fallo y lam6 la Plataforma Java 2, Enterprise Edition (J2EE). La idea subyacente a la plataforma J2EE es proporcionar u n estindar sencillo y unificado para aplicaciones distribuidas e n u n modelo de aplicaci6n basado en componentes. En el resto del capitulo, y por supuesto en el resto del libro, analizaremos lo que aporta J2EE a1 desarrollo del lado servidor con Java.

Estilos de arquitectura de empresa


Antes de que entremos de lleno en la arquitectura de J2EE, es necesario que consideremos 10s estilos de arquitectura de las aplicaciones distribuidas contemporineas: las arquitecturas de nivel2, nivel3 y nivel n. El propdsito de esta seccidn es principalmente capacitar a1 lector para reconocer el alcance y la localizacidn de estos patrones. Sin embargo, debemos tener presente que en realidad posiblemente nuestras aplicaciones requieran patrones mis complejos o en ocasiones una combinacidn de tstos. Aunque estos estilos de arquitectura se encuentran con bastante frecuencia en las empresas de la actualidad, merece la pena sefialar que estos estilos surgieron debido a la llegada de nuevas plataformas de hardware para clientes y servidores mis baratas y de tecnologias de redes. Anteriormente, 10s motores de las empresas eran sistemas principales con todos 10s servicios informiticos (desde la generacidn usuariointerfaz hasta procesamiento de transacciones de gran volumen) centralizados. Consecuentemente, la tecnologia cliente-servidor fue lo que provoc6 una automatizacidn masiva de la empresa. Los sistemas cliente-servidor tipicos estin basados en la arquitectura de dos niveles, donde existe una clara separacidn entre 10s datos y la 16gica presentacion/empresa. Estos sistemas estin generalmente controlados por datos, siendo el servidor, en gran cantidad de ocasiones, un servidor de base de datos. Aunque este enfoque nos permite compartir datos en la empresa, tiene muchos inconvenientes.

Arquitectura de dos niveles


En una aplicaci6n tradicional de 2 niveles, la carga de procesamiento es facilitada el PC cliente mientras que el servidor actua simplemente como controlador del trifico entre la aplicacidn y 10s datos. Como resultado, el rendimiento de la aplicacidn no s61o sufre debido a 10s recursos limitados del P C sino que el trifico de la red tambitn tiende a aumentar. Cuando la aplicacidn completa es procesada en un PC, la aplicaci6n es forzada a realizar multiples peticiones de datos antes incluso de presentar algo al usuario. Estas mdtiples peticiones de bases de datos pueden sobrecargar la red:

Plataforma J2EE

Aplcacdn

'

O t r o problerna tipico relacionado con el enfoque de 2 niveles es el del rnantenimiento. Incluso el rnenor carnbio realizado a una aplicaci6n puede conllevar una completa alteraci6n en la base de usuario. Aunque sea posible autornatizar el proceso, todavia debe enfrentarse a la actualizacidn de cada instalaci6n de cliente. Es mis, algunos usuarios puede que no estkn preparados para una alteraci6n total y posiblernente ignoren 10s cambios rnientras que otro grupo puede que insista en realizar 10s cambios de inrnediato. Esto puede provocar que diferentes instalaciones de cliente utilicen diferentes versiones de la aplicaci6n.

Arquitectura de tres niveles


Para enfrentarse a estos ternas, la cornunidad de software desarroll6 la noci6n de una arquitectura de 3 niveles. Una aplicaci6n se divide en tres capas 16gicas distintas, cada una de ellas con un grupo de interfaces perfectamente definido. La prirnera capa se denornina capa de p r e s e n t a c i h y norrnalmente consiste en una interfaz grifica de usuario de algun tipo. La capa interrnedia, o capa de ernpresa, consiste en la aplicaci6n o 16gica de ernpresa, y la tercera capa, la capa de datos, contiene 10s datos necesarios para la aplicaci6n. La capa interrnedia (lbgica de aplicaci6n) es bisicamente el codigo a1 que recurre el usuario (a travCs de la capa de presentaci6n) para recuperar 10s datos deseados. La capa de presentaci6n recibe entonces 10s datos y 10s formatea para su presentacibn. Esta separaci6n entre la 16gica de aplicaci6n de la interfaz de usuario ariade una enorrne flexibilidad a1 diserio de la aplicaci6n. Puede construirse y desplegarse multiples interfaces de usuario sin carnbiar en absoluto la 16gica de aplicaci6n, siernpre que la 16gica de aplicaci6n presente una interfaz clararnente definida a la capa de presentacibn. Corno veri rnis adelante en este capitulo, y e n el resto del libro, J2EE ofrece diversas abstracciones para satisfacer las necesidades de cada una de estos niveles. Por ejernplo, 10s EJB ofrecen rnecanisrnos para abstraer tanto el acceso a datos corno la 16gica de empresa. De un rnodo similar, 10s servlets y las Piginas JavaServer le perrniten abstraer la capa de presentaci6n y su interacci6n con la capa de ernpresa. La tercera capa contiene 10s datos necesarios para la aplicaci6n. Estos datos consisten en cualquier fuente de inforrnaci611, incluido una base de datos de empresa corno Oracle o Sybase, un conjunto de documentos XML o incluso un servicio de directorio corno el servidor LDAP. Adernis del tradicional rnecanisrno de alrnacenarniento relacional de bases de datos, existen rnuchas fuentes diferentes de datos de ernpresa a las que pueden acceder sus aplicaciones:

Capitulo

1
lnterfaz d e Usuario

Documentos
XML

Sin embargo, todavia n o hemos finalizado nuestra subdivisidn de la aplicaci6n. Podemos dar un paso m i s e n la segregation para crear una arquitectura de n niveles.

Arquitectura de n niveles
C o m o sugiere el titulo, n o hay un m o d 0 m i s precis0 de definir las capas de aplicaci6n para un sistema de n niveles. D e hecho, este tip0 de sistema puede dar cabida a varias configuraciones diferentes. En una arquitectura de n niveles, la 16gica de aplicaci6n e s t i 16gicamente dividida p o r funciones y n o fisicamente. U n a arquitectura de n niveles se descompone en las siguientes partes:
0

U n a interfaz d e usuario que maneja la interacci6n del usuario con la aplicaci6n. ~ s t puede a ser un navegador W e b ejecutado mediante un cortafuegos, una aplicaci6n de escritorio m i s laboriosa o incluso un dispositivo inalimbrico. U n a 16gica d e presentaci6n que define lo que muestra la interfaz de usuario y c o m o son gestionadas las demandas del usuario. Dependiendo de las interfaces de usuario que se mantengan, puede que sea necesario contar con versiones de la 16gica de presentaci6n ligeramente diferentes para satisfacer a1 cliente adecuadamente. U n a 16gica d e empresa que modele las reglas de empresa de la aplicacibn, a menudo a traves de la interacci6n con 10s datos de la aplicaci6n.

o Semicios d e infraestructura que proporcionen la funcionalidad adicional requerida p o r 10s componentes d e la aplicacion, tales c o m o mensajeria y apoyo transactional.
0

La capa d e datos donde residen 10s datos de la empresa.

Plataforma J2EE

Navegador
I

~
Cortafuegos

Log~cade Empresa

Documentos XML

Las aplicaciones basadas en esta arquitectura emplean esencialmente el patrdn Model-ViewController ( M V C ) . Lo que esto sign+ca fundamentalmente es que 10s datos (el modelo) son independientes respecto de la presentacidn de la informacidn (la vista). En una posicidn intermedia se encuentra la 16gica de aplicacidnlempresa (el controlador) que controla el jlujo de informacidn. De este modo, uria aplicacidn es disefiada a partir de estos tres componentes funcionales (modelo, vista y controlador) interactuando erztre s i

Arquitectura de empresa
Hasta el momento nos hemos centrado realmente en una sola arquitectura de aplicacion; nos arriesgamos a considerar estas aplicaciones "tuberias". En otras palabras, puede que terminemos con diferentes aplicaciones (posiblemente incluso con diferentes arquitecturas) que no se cornunican entre si. En una ernpresa, intentarnos crear una arquitectura cohesiva que incorpore diferentes aplicaciones. Antes que un carnbio en la arquitectura (la arquitectura de ernpresa es bdsicamente n niveles) necesitamos un carnbio en la percepcion. Para convertir un sisterna n niveles en un sisterna de ernpresa, simplernente necesitamos ampliar el nivel interrnedio perrnitiendo la existencia de multiples objetos de aplicacion en lugar de una unica aplicacion. Estos objetos de aplicacion deben tener una interfaz individual que les perrnita funcionar entre si. Una interfaz puede concebirse corno un contrato. Cada objeto afirma a travis de su interfaz que aceptari ciertos pardmetros, que realizari ciertas operaciones y devolvera un conjunto especifico de resultados. Los objetos de la apkaci6n se comunican entre si utilizando sus interfaces, corno muestra el siguiente diagrarna:

Capitulo 1

Forma HTML

lnterfaz

lnterfaz

lnterfaz

/ S~stemaRemoto ;
L-

Documentos 1 XML 1

Con la arquitectura de empresa, podemos tener multiples aplicaciones utilizando un conjunto comun de componentes a traves de una organizaci6n. Esto promueve la normalizaci6n de la prictica empresarial gracias a la creaci6n de un Gnico conjunto de funciones de empresa a1 que puede acceder toda la organizaci6n. Si la norma de una empresa cambia, dichos cambios deben trasladarse tambien a1 "objeto de empresa" y, si es necesario, a la interfaz asociada y consecuentemente a cualquier objeto que acceda a la interfaz. Observe, sin embargo, que ciertas funcionalidades de 10s sistemas legados existentes no pueden eliminarse y que debe desarrollarse un "envoltorio" (o interfaz) especifico a esta funcionalidad en el nivel intermedia.

Es importante sefialar que a la hora de diseiiar un objeto y su interfaz, es conveniente hacer que la interfaz sea lo m6s generica posible para evitar cambios en el futuro. Debido que a otros objetos se comunican con la interfaz y no con el objeto en si mismo, 10s cambios realizados a1 objeto, y no a la interfaz, son relativamente sencillos y ripidos.
Observe que, en todos estos patrones, las interfaces de usuario son la parte que aparece en la parte superior de cada diagrama. A partir de estos diagramas, puede obtener la impresi6n de que las interfaces de usuario son las que siempre dirigen 10s sistemas. Aunque ksta es la forma mis comGnmente visible de interacci6n de sistema, a1 considerar la integraci6n de aplicaciones intra e inter-empresa, y en 10s procesos entre empresas, comprobari que las aplicaciones interactGan con otras aplicaciones. N o obstante, la mayoria de las tecnologias que examinaremos y 10s disefios que encontrari en este libro tambien se aplican a estos sistemas.

Plataforma J2EE

La plataforma JZEE
C o m o podri comprobar en el resto del libro, J2EE es una de las mejores soluciones encontradas hasta el momento para satisfacer las demandas de la emprcsa de hoy en dia. J2EE especifica tanto la infraestructura para gestionar sus aplicaciones, como 10s sewicios API para construir sus aplicaciones. La plataforma J2EE es esencialrnente un entorno distribuido aplicaci6n-servidor, un entorno Java que ofrece:
0 U n conjunto de varios API de extension Java para construir aplicaciones. Estos API definen un

modelo de programacibn para aplicaciones J2EE. U n a infraestructura de periodo de ejecuci6n para albergar y gestionar aplicaciones. ~ s t es e el periodo de ejecuci6n en el que residen sus aplicaciones. Las aplicaciones que puede desarrollar con estos dos elementos pueden ser programas para controlar piginas Web o componentes para implementar transacciones complejas de bases de datos, o incluso applets de Java, todos ellos distribuidos por la red.

Periodo de ejecucion de JZEE


Si bien JZEE asocia 10s API que han existido de una forma u otra durante a l g h tiempo, quizis su aspecto m i s significative sea la abstracci6n de la infraestructura del periodo de ejecucion. Observe que la especificaci6n J2EE no especifica como deberia o podria construirse un periodo de ejecuci6n. Esto provoca una clara demarcaci6n entre las aplicaciones y la infraestructura del periodo de ejecuci6n. Esta demarcaci6n permite al periodo de ejecuci6n abstraer la mayor parte de 10s sewicios de infraestructura que 10s desarrolladores de programas de empresa han intentado construir tradicionalmente por su cuenta. C o m o resultado, los desarrolladores de programas de la aplicaci6n JZEE s61o podian centrar sus esfuerzos en la 16gica de aplicacibn y servicios relacionados, mientras relegaban el periodo de ejecucibn para todos 10s servicios relacionados con la infraestructura. Sin embargo, icuiles son 10s requisitos de infraestructura para aplicaciones de empresa? Es interesante seiialar que el desarrollo de aplicaciones en un entorno de ritmo crecimiento ripido, como Internet, tiene como resultado normalmente diseiios efimeros. Por otro lado, a la hora de considerar 10s aspectos de diseiio a largo plaza, podemos tener dificultades para encontrar un termino medio entre las demandas a corto plazo y a largo plazo. Existen tecnologias que se prestan a un ripido desarrollo y otras tecnologias que permiten construir aplicaciones teniendo en cuenta este tip0 de intereses a largo plazo como la reusabilidad, coste de rnantenimiento, etc. A menudo, estos dos tipos n o se combinan, per0 JZEE es lo suficientemente flexible como para construir aplicaciones que incluyan ambos. La raz6n es que J2EE le permite construir cada capa de su aplicaci6n en combinacibn libre con todas las otras capas. Cada capa puede consecuentemente evolucionar para cubrir sus respectivas necesidades de evolucibn. D c este modo, ajustindose a un sistema disenado sobre interfaces, la implementaci6n es rnuy ampliable. Adernis de especificar una serie de API estbndar, la arquitectura de J2EE tambitn proporciona un medio uniforme de acceder a 10s sewicios a escala de la plataforma a travts de su entorno de periodo de ejecucibn. Estos servicios incluyen transacciones distribuidas, seguridad, mensajes, etc. Antes de pasar a 10s detalles del enfoque de J2EE, examinemos el procesamiento informitico distribuido tradicional. Hasta la llegada de J2EE, el procesamiento informitico distribuido era considerado, en general, programacibn cliente-sewidor. Grabariarnos una aplicaci6n de sewidor implementando una interfaz, una aplicacion de cliente para conectar con el sewidor y entonces iniciar el sewidor y el cliente. Aunque este

Capitulo 1
proceso parece bastante sencillo, en la prictica existen varios obsticulos criticos, dependiendo de la tecnologia utilizada. Por ejemplo, pensemos en un objeto CORBA para construir aplicaciones distribuidas. El procedimiento tipico para construir objetos CORBA de lado servidor empezaria especificando una interfaz, utilizando el Lenguaje de Definici6n de Interfaces (IDL), para cada objeto. Los pasos siguientes incluyen compilar este IDL para generar "stubs" y "esqueletos" para el lenguaje que elija, implementando el objeto basado en el esqueleto, grabando despues la aplicaci6n de cliente, preparando el entorno, etc. En este caso, el stub es la clase que representa el objeto CORBA en el lado cliente. El esqueleto proporciona el metodo con el que es implementada la 16gica del lado servidor. Este procedimiento en si mismo no es complicado y puede automatizarse ficilmente. Como iri aprendiendo en este libro, 10s EJB requieren tambitn algunos de estos pasos y son similares en concept0 a 10s objetos CORBA. Considere ahora que nuestros servidores, al igual que 10s clientes, necesitan acceder a servicios tales como transacciones distribuidas, mensajeria, etc. Para hacer uso de estos servicios, seria necesario que aiiaditramos una importante proporci6n de c6digo de instalaci6n a nuestras aplicaciones. En muchas ocasiones, seri necesario que instalemos y configuremos diferentes soluciones de software intermedio, y que realicemos llamadas API a 10s API especificos de vendedor para acceder a 10s servicios. Ademis de servicios tales como el acceso a bases de datos relacionales, la mayoria de estos servicios son de propiedad o no estindar. El resultado es que nuestras aplicaciones serin mis complejas, invertirin mis tiempo y serin mis caras de desarrollar, gestionar y mantener. Ademis de tener que gestionar todos estos API diferentes, existe otra demanda critica en las aplicaciones del lado servidor. En el lado servidor, 10s recursos son escasos. Por ejemplo, no podemos permitirnos crear el mismo numero de objetos podriamos crear normalmente en aplicaciones del lado cliente. Otros recursos del lado servidor que requieren especial atenci6n incluyen hilos de ejecuci6n (threads), conexiones de bases de datos, seguridad, transacciones, etc. Construir a medida una infraestructura que maneje este tip0 de recursos ha sido siempre un desafio. Esta tarea resulta casi imposible en la economia de Internet. iSe molestaria en construir una reserva de conexibn, o un objeto cache, o "una elegantel' capa de objeto para acceso a bases de datos, cuando su ciclo de vida de desarrollo es s610 de tres meses? Debido a que estos requisitos de lado servidor son bastante comunes a una amplia variedad de aplicaciones, es mis apropiado considerar una plataforma que cuente con soluciones integradas. Esto nos permite separar estos aspectos de infraestructura de 10s aspectos mis directos relacionados con traducir sus requisitos de aplicaci6n en un software que funcione. El periodo de ejecuci6n de J2EE se enfrenta a dichos aspectos. Fundamentalmente, dejamos que sea el vendedor de servidor J2EE quien implemente 10s rasgos especificos de acuerdo con las normas establecidas. Como ya hemos mencionado anteriormente, J2EE no especifica la naturaleza y estructura del periodo de ejecuci6n. En su lugar, introduce lo que se denomina contenedor y mediante 10s API de JZEE, especifica un contrato entre contenedores y aplicaciones. Tendri mis detalles sobre este contrato mis adelante. Antes de examinar con mis detalle 10s contenedores de JZEE, revisemos brevemente 10s API de J2EE.

Los API de JZEE


Las aplicaciones distribuidas requieren acceso a una serie de servicios de empresa. Los servicios tipicos incluyen procesamiento de transacciones, acceso a bases de datos, mensajeria, multihilos (multithreading), etc. La arquitectura de JZEE unifica el acceso a estos servicios en un API de servicios de empresa. Sin embargo, en lugar de tener que acceder a estos servicios a travts de interfaces de propietario o no estindar, 10s programas de aplicaci6n en J2EE pueden acceder a estos API mediante el contenedor. Una tipica plataforma J2EE comercial (o servidor de aplicaci6n J2EE) incluye uno o mis contenedores y el acceso a 10s API de empresa viene especificado por la J2EE.

Plataforma J2EE
Fijese en que 10s servidores de aplicacidn J2EE no necesitan implementar estos seruicios ellos mismos; 10s contenedores s61o deben proporcionar acceso a cada implementaci6n de servicio a travb de u n API de J2EE. Por ejemplo, una impfementaci6n J2EE puede delegar las llamadas API de Java Message Service a una solucidn de sofmare intermedio orientada a mensajes. Otra implementaci6n podria incluir una sofucidn de software intermedio orientada a mensajes dentro de un contenedor.
La especificacion de la plataforma J2EE 1.3 incluye un grupo de extensiones estindar Java que cada plataforrna J2EE debe mantener:
0 JDBC 2.0

Mis especificarnente, JDBC 2.0 Optional Package. Este API rnejora el API estindar de JDBC 2.0 afiadiendo rnedios mis eficientes de obtener conexiones, reserva de conexibn, transacciones distribuidas, etc. Observe que la siguiente versi6n de JDBC, el API de JDBC 3.0, combina la extensi6n API con el API JDBC habitual. Quizis futuras versiones de J2EE incluyan JDBC 3.0.
0 Enterprise JavaBeans (EJB) 2.0 Especifica una estructura de componentes para aplicaciones multidistribuidas multinivel . Proporciona un medio estindar para la definici6n de componentes de lado servidor y especifica una rica infraestructura de period0 de ejecuci6n para albergar cornponentes en el lado servidor.
0 Java Servlets 2.3

El API Java Servlet proporciona abstracciones orientadas a1 objeto para construir aplicaciones Web dinirnicas.
0 Java Server Pages (JSP) 1.2

Esta extensi6n refuerza un poco rnis las aplicaciones Web de J2EE proporcionando desarrollo de aplicaciones Web dirigidas por un rnodelo.
0 Java Message Service (JMS) 1.0 JMS ofrece un API Java para colas de rnensaje y publica y suscribe tipos de servicios de software intermediario orientados al rnensaje.
O Java Transaction API (JTA) 1.0

Este API esti destinado a irnplernentar aplicaciones transaccionales distribuidas.


0 JavaMaill.2 Este API proporciona una estructura independiente de la plataforma y del protocolo para construir aplicaciones de e-mail basadas en Java.
O JavaBeans Activation Framework (JAF) 1.0

Este API es necesario para el API JavaMail. El API JavaMail utiliza JAF para deterrninar 10s contenidos de un rnensaje MIME (Multipurpose Internet Mail Extension) y deterrnina quC operaciones apropiadas pueden realizarse en diferentes partes de un mensaje.
0 API Java para XML Parsing (JAXP) 1.1 Este API proporciona abstracciones para analizadores XML y API de transformaci6n. JAXP ayuda a aislar analizadores especificos XML, o irnplernentaciones D O M (Document Object Model), o API de transforrnaci6n XSLT de codigos de aplicacidn J2EE.
O Java Conector Architecture (JCA) 1.0

Este API ha sido incluido recientemente en J2EE y proporciona un rnedio para integrar cornponentes de aplicacion J2EE para sistemas de informaci6n legados.
0 Java Authenticaction and Authorization Service (JAAS) 1.0 Este API proporciona rnecanismos de autentificacion y autorizacion para las aplicaciones J2EE.

Capitulo 1
La mayoria de estos API son especificaciones, independientes de implernentacion. Es decir, se deberia poder acceder a 10s semicios proporcionados por estos API de un mod0 estindar, con independencia de como son implementados. Los API especificos de J2EE mencionados anteriormente se suman a 10s siguientes API de J2SE:
0

API Java Interface Definition Language (IDL) Este API permite a 10s componentes de aplicacion J2EE invocar objetos CORBA via I I O P (vtase mis adelante). Este API proporciona las instalaciones de programaci6n de bases de datos bisicas.

0 JDBC Core API


O

API RMI-IIOP Proporciona una implementaci6n del habitual API Java Remote Meted Invocation (RMI) sobre Internet Inter.-ORB Protocol (IIOP). Salva la distancia entre las aplicaciones RMI y CORBA. Este es el protocolo de comunicaci6n asignado a utilizar entre contenedores J2EE. API J N D I El API Java Naming and Directory Interface (JNDI) normaliza en acceso a diferentes tipos de semicios de designaci6n y directorio disponibles en la actualidad. Este API esti diseiiado para ser independiente de cualquier implementation especifica de semicio de designation o directorio. J2SE tambien especifica una interfaz proveedora de semicio J N D I (SPI), para ser implementada por proveedores de servicios de designacidn y directorio.

Examinaremos mks detalladamente estos API en posteriores apartados de este capitulo.

Arquitectura J2EE

- Contenedores

Como ya hemos visto en la secci6n anterior, una tipica plataforma comercial J2EE incluye uno o mis contenedores. Pero {qut exactamente un contenedor? U n contenedor J2EE es u n periodo de ejecuci6n para gestionar 10s componentes de la aplicaci6n desarrollados seglin las especificaciones del API y destinados a proporcionar acceso a 10s API de J2EE. Mas alli de la identidad asociada a1 periodo de ejecucirin, J2EE no especifica ninguna identidad para contenedores. Esto se traduce en una gran flexibilidad para conseguir una serie de caracteristicas dentro del periodo de ejecuci6n del contenedor. La siguiente figura muestra la arquitectura de J2EE en ttrminos de sus contenedores y sus API.

Plataforma J2EE

Contenedor de Applet
-

HTTP SSL
Contenedor Web
I
I----+[

Contenedor E3B

JSP

:ervlet

Contenedor Chente~ de Apl~cac~dn I

HTTP SSL

Esta arquitectura muestra cuatro contenedores:


0 0

U n contenedor Web para albergar sewlets Java y piginas JSP. U n contenedor EJB para albergar componentes Enterprise JavaBean.

0 U n contenedor applet para albergar applets Java. 0 U n contenedor de aplicaci6n cliente para albergar aplicaciones Java estindar.

En este libro, nuestro centro de atencio'n se limita knicamente a 10s contenedores Web y EJB.
Cada uno de estos contenedores proporciona un entorno de periodo de ejecuci6n para 10s respectivos componentes. Los componentes J2EE tambiCn son denominados objetos gestionados, ya que estos objetos con creados y gestionados en el interior del periodo de ejecuci6n del contenedor. En la figura anterior, 10s bloques verticales situados en la parte inferior de cada contenedor representan 10s API de T2EE. Ademis del acceso a estos API a nivel infraestructura. cada contenedor tambiCn implementa el correspondiente API especifico a cada contenedor (API Java Servlet para el contenedor Web y el API EJB para el contenedor EJB). Los rectingulos (servlets, piginas JSP y 10s EJB) de esta figura son 10s programas que se desarrollan y se albergan en estos contenedores. En el lenguaje J2EE, estos programas se conocen como cornponentes de aplicaciones.

Observe que la figura anterior no incluye 10s API J2SE enumerados anteriormente, es decir, el Java I D L , memoria J D B C , RMI-IIOP y J N D I .

Capitulo 1
En esta arquitectura, existen principalmente dos tipos de clientes:

o Clientes Web, que se ejecutan normalmente en navegadores Web.


Para estos clientes, la interfaz de usuario es generada en el lado sewidor como HTML o XML y es descargada y despuks convertida por 10s navegadores. Estos clientes utilizan http para comunicarse con contenedores Web. Los componentes de aplicaci6n en 10s contenedores Web incluyen sewlets Java y piginas JSP. Estos componentes implementan la funcionalidad requerida por 10s clientes Web. Los contenedores Web son 10s responsables de aceptar solicitudes por parte de 10s clientes Web y de generar respuestas con la ayuda de 10s componentes de la aplicacion. Otros tipos de clientes relacionados incluyen dispositivos m6viles habilitados por la Web capaces de generar WML (Wireless Markup Language) o cHTML (Compact HTML). Para estos clientes, el contenido puede ser generado directamente, o bien el contenido generado como XML puede ser transformado en estos lenguajes de marcado utilizando hojas de estilo XML.
U Los clientes EJB son aplicaciones que acceden a componentes EJB en contenedores EJB.

Existen tres posibles tipos de clientes EJB. La primera categoria esti constituida por 10s clientes de aplicacion. Los clientes de aplicacidn son aplicaciones autosuficientes que acceden a 10s componentes EJB utilizando el protocolo RMI-IIOP. La segunda categoria de clientes de aplicacion est6 formada por componentes del contenedor Web. Es decir, 10s sewlets de Java y las piginas JSP tambikn pueden acceder a 10s componentes EJB a travks del protocolo RMI-IIOP del mismo mod0 que 10s clientes de aplicacion. La d t i m a categoria es otro EJB ejecutado dentro del \ contenedor EJB. Estos se comunican a travks de llamadas estindar de mktodo Java por medio de de una interfaz local (esta caracteristica es una novedad de J2EE 1.3). En 10s dos casos, 10s clientes acceden a 10s componentes de la aplicacion a travPs de sus respectivos contenedores. Los clientes Web acceden alas piginas JSP y a 10s sewlets Java a travks del contenedor Web, y 10s clientes EJB acceden a 10s componentes EJB a travks del contenedor EJB.

Arquitectura de contenedor
Despuks de haber analizado las partes integrantes de JZEE, volvamos a nuestro anilisis de la arquitectura y estudiemos la arquitectura de un contenedor J2EE:
Contrato de Contenedor
--

i. z
@

Componentes de Apl~cac~bn
Descriptor de

lrnplernentaclon

Componentes

lrnplernentac~on

lrnplernentac~on

Plataforma j2EE
En esta arquitectura, corno desarrolladores de programas estarnos obligados a proporcionar 10s siguientes elernentos:
0

Componentes de aplicaci6n Corno ya hernos visto en la secci6n anterior, 10s componentes de aplicaci6n incluyen servlets, piginas JSP, EJB, etc. En J2EE, 10s cornponentes de aplicaci6n pueden ser incluidos en ficheros en archivo. Descriptores de implementaci6n U n descriptor de irnplernentaci6n es un archivo XML que describe 10s cornponentes de aplicaci6n. Tarnbitn incluye inforrnaci6n adicional requerida por contenedores para gestionar de un rnodo efectivo 10s cornponentes de aplicaci6n.

El resto de esta figura forrna el contenedor. La arquitectura de un contenedor puede dividirse en cuatro partes:
0

C o n t r a t o de contenedores U n conjunto de API especificados por el contenedor, que sus cornponentes de aplicacidn estin obligados a arnpliar o irnplernentar.

API de servicio de contenedor


Los servicios adicionales proporcionados por el contenedor, que cornhrnente son requeridos por todas las aplicaciones en el contenedor.

Servicios declarativos Servicios que el contenedor introduce en sus aplicaciones, basados en la descripci6n de irnplernentaci6n proporcionada por cada cornponente de aplicaci6n, corno la seguridad, las transacciones, etc. O t r o s servicios de periodo de ejecucibn, relacionados con ciclos de vida de 10s componentes, reserva de recursos, recolecci6n de basura, etc.

o O t r o s servicios de contenedores

Examinernos a continuaci6n cada uno de 10s elementos anteriores rnis detenidarnente.

Contratos de componentes
Corno ya hernos rnencionado anteriormente, el propbsito bisico del contenedor en la arquitectura J2EE es proporcionar un periodo de ejecuci6n para 10s cornponentes de apkaci6n. Es decir, se crean ejernplares de 10s cornponentes de aplicaci6n y se invocan en el JVM del contenedor. Esto convierte a1 contenedor en responsable de la gesti6n del ciclo de vida de 10s cornponentes de la aplicaci6n. Sin embargo, si estin llarnados a ser gestionables en el periodo de ejecuci6n del contenedor, estin obligados a guiarse por ciertos contratos especificados por el contenedor. En otras palabras, las aplicaciones deben ser desarrolladas de acuerdo con un rnarco de operaci6n definido. Para cornprender rnejor este aspecto, considerernos un applet Java. Norrnalrnente, un applet es descargado por el navegador, instanciado e inicializado en el JVM del navegador. Es decir, el applet vive en el periodo de ejecuci6n proporcionado por el JVM del navegador. Sin embargo, para que el contenedor tenga la capacidad de crear, inicializar, e invocar rnttodos sobre cornponentes de aplicacibn, es necesario que 10s cornponentes de aplicaci6n irnplernenten o arnplien ciertas interfaces o clases Java. Por ejernplo, si tornarnos de nuevo el ejernplo del applet, un applet Java esti obligado a arnpliar la clase j ava applet .Applet especificada por el JDK. El JVM del navegador espera que 10s applets amplien esta clase. Esto perrnite al JVM del navegador llarnar a 10s rnttodos init ( ) , st art ( ) , s t o p ( ) y destroy ( ) de sus applets. Estos rnitodos controlan el ciclo de vida de un applet; si su applet no arnplia la clase j ava applet .Applet, el JVM del navegador no cuenta con 10s rnedios para llarnar a estos rnttodos y controlar su ciclo de vida.

-'En JZEE, todos 10s cornponentes de aplicaci6n son instanciados e inicializados en el JVM del contenedor.
Adernis, debido a que 10s componentes de aplicaci6n JZEE son siernpre remotos a1 cliente, 10s clientes n o pueden invocar rnitodos directamente en estos cornponentes; de hecho, 10s clientes realizan solicitudes a1 -senidor de las aplicaciones y es el contenedor el que realmente invoca 10s rnitodos. Puesto que el proceso del contenedor es el h i c o punto de entrada a 10s componentes de la aplicaci6n, es necesario que todos 10s cornponentes de la aplicaci6n sigan el contrato especificado por el contenedor. En JZEE, este contrato esti concretado en interfaces y clases que las clases del usuario irnplementan o amplian, con norrnas adicionales que la definici6n del componente debe seguir. Existe una consecuencia irnportante de este contrato de componente. Todos 10s componentes de aplicaci6n JZEE son gestionados. La gesti6n incluye la ubicacibn, instanciaci6n, inicializaci6n, invocaci6n de semicio y elirninaci6n de componentes del semicio. Estos aspectos del ciclo de vida del componente estin bajo la re~~onsabilidad del contenedor y la aplicaci6n no tiene control directo. Analicemos a continuacion 10s diversos contratos especificados por el JZEE. En el caso de 10s contenedores Web, 10s componentes de aplicaci6n Web deben seguir 10s API de Java Semlet y de JSP. En este modelo, todos 10s semlets Java deben arnpliar la clase j a v a x .S e r v l e t .h t t p . H t t p S e r v l e t , e implernentarciertos rnitodos de estaclase tales comodoGet ( ) , d o p o s t ( ) , etc. Del mismo modo, a1 ser cornpilado, las clases correspondientes a las piginas JSP amplianlaclasejavax. S e r v l e t .j s p . H t t p J s p P a g e . En el caso de 10s contenedores EJB, 10s beans de sesi6n y de entidad de ernpresa deben tener interfaces j a v a x .e j b .EJBHome y j a v a x .e j b . E JBObj e c t especificados, alavez que implementan unainterfaz j a v a x . e j b . S e s s i o n B e a n o j a v a x . e j b . E n t i t y B e a n . Del mismo rnodo, 10s beans orientados a mensajes deben irnplernentar las interfaces j a v a x .e j b . M e s s a g e D r i v e n B e a n y j a v a x . jmx . M e s s a g e L i s t e n e r . Cornoveri en el capitulo 14, las especificaciones e implementaciones de componente tambiin deben seguir ciertas reglas. Aparte de las interfaces, todas estas reglas formafi parte del contrato de componente para componentes EJB.

API de servicio de contenedor


Corno hernos visto anteriormente, la plataforma JZEE define un conjunto de extensiones estindar de Java que cada plataforrna debe mantener. Los contenedores J2EE proporcionan una abstracci6n a nivel de semicio de 10s API. Corno resultado, el usuario puede acceder a 10s API de semicio tales como JDBC, JTS, JNDI, JMS, etc. dentro del contenedor, como si el contenedor subyacente 10s implernentara. U n contenedor en la arquitectura de J2EE proporciona una visidn consolidada de varios API de empresa especificados e n la plataforma J2EE. En JZEE, 10s componentes de aplicaci6n pueden acceder a estos API a travis de objetos apropiados creados y publicados en el semicio o implernentaci6n JNDI. Por ejemplo, cuando queremos utilizar JMS en nuestros cornponentes de aplicaci61-1,configuraremos nuestra plataforma JZEE para crear factorias de conexi6n JMS, colas de rnensajes y apartados, y publicar estos objetos en el semicio JNDI. Entonces nuestras aplicaciones pueden consultar el JNDI, obtener referencias para estos objetos, e invocar rnitodos. En este proceso, no importa si la plataforma JZEE tiene una implementaci6n JMS incorporada o si esti utilizando una soluci6n de software intermediario de mensajes de tercero. Consideremos de nuevo 10s applet de Java. Por ejemplo, si queremos reproducir un archivo de audio desde un applet, llamariamos a1 mitodo p l a y ( ) definido en el superclase ( ja v a .a p p l e t . A p p l e t ) , con un URL apuntando a1 archivo de audio. En este caso, la funcionalidad para reproducir archivosde audio es implementada por la superclase. Este es uno de 10s enfoques para la reutilizaci6n de c6digo. Una mejor alternativa a este enfoque es delegar esta funcionalidad en un componente cornfin. Es necesario que un

Plataforma J2EE
componente de este tip0 no sea una parte de la misma jerarquia de herencia. Lo unico que se requiere es una referencia a un objeto que implemente esta funcionalidad. Una vez que nuestra aplicaci6n pueda obtener una referencia de este objeto, ~ o d e m o delegar s la funcionalidad "play" a ese objeto. Una importante ventaja de este enfoque es que permite que otros objetos procedentes de mis de una jerarquia de herencia accedan la funcionalidad "play". En el caso de aplicaciones distribuidas es mls complicado, ya que 10s servicios son remotos. S61o como analogia, consideremos el mismo componente de audio ejecutado como un servidor distinto. iC6mo obtenemos una referencia a este componente? La soluci6n es permitir a la plataforma J2EE crear el componente de audio y publicar su nombre en un servicio de designaci6n (es decir, en JNDI) disponible para su aplicaci6n. Esto proporciona un mitodo simplificado de acceso a 10s API de servicio. Tambiin nos permite acoplar diferentes implementaciones de estos servicios sin alterar las aplicaciones utilizando 10s semicios. El siguiente esquema ilustra esta posibilidad:

xy de Componente Aud~o Proceso Chente A

--I

lmplementac~on de Componente Audlo Proceso de Serv~dorAudlo

Buscar Proxy

Publ~carComponente Audlo

Observe la libre conexi6n entre la implementaci6n y el cliente. Siempre que la interfaz expuesta por el proxy se mantenga sin alterar, la implementaci6n puede ser modificada sin afectar el c6digo cliente. Esta es la forma mis adecuada de abstracci6n en el lado servidor, ya que no s61o utiliza delegaci6n en lugar de herencia, sino que tambiin reduce el acoplamiento. Todos 10s API de servicio J2EE utilizan el enfoque anterior para proporcionar semicios a las aplicaciones. Las siguientes son las implicaciones clave de este enfoque: Como Gnico estindar que puede establecerse en una variedad de sistemas debases de datos existentes, sistemas de procesamiento de transacciones, servicios de designaci6n y directorio, etc., el API de servicio elimina la heterogeneidad inherente relacionada con la agrupaci6n de estas tecnologias en nuestras aplicaciones. En J2EE, estos servicios tambiin estin integrados estrechamente en el modelo de programacibn. En proximos capitulos, veremos c6mo acceder a estos API sin interrupciones a partir de nuestros componentes de apkaci6n y clientes.

, i '
u

O La plataforma J2EE tambiin especifica un mecanismo uniforme para acceder a estos servicios.

Servicios declarativos
Uno de 10s aspectos importantes de la arquitectura de J2EE es su capacidad para introducir servicios para componentes de aplicaci6n. Esti basado en declaraciones especificadas fuera de nuestros componentes de aplicaci6n. La arquitectura de J2EE proporciona medios sencillos de especificar tales declaraciones. Se denominan descriptores de implementacih.

Capitulo

1
U n descriptor de implementaci6n define el contrato entre el contenedor y el componente. C o m o desarrolladores aplicaciones, debemos especificar u n descriptor de implementaci6n para cada grupo de componentes de aplicacibn.

Por ejemplo, un conjunto de componentes EJB puede ser descrito conjuntamente en un dnico archivo de descriptor de implernentacion. De mod0 similar, en el caso de 10s contenedores Web, cada aplicacion Web debe tener un descriptor de implementaci6n especificado. Dependiendo del tip0 de componente, ciertos tipos de servicios (tales como transacciones, seguridad, etc) pueden ser especificados en el descriptor de implementaci6n. El prop6sito de este enfoque es minimizar la programaci6n de la aplicacion requerida con el fin de hacer uso de tales servicios.
7

/'El mitodo estindar de invocar servicios es mediante invocaci6n explicita. Por ejemplo, para implementar transacciones para el acceso a bases de datos, podemos empezar por programar una transacci6n antes de acceder a la base datos y realizar o deshacer la transacci6n una vez completados 10s mitodos de empresa. En el caso de invocaci6n declarativa, nuestros componentes de aplicaci6n no necesitan explicitamente empezar y detener transacciones. En su lugar, podemos especificar en el descriptor de implementaci6n que nuestros mitodos de empresa deben ser invocados en una nueva transaccibn. Basindose en esta informaci6n, el contenedor puede iniciar automlticamente una transaccion siempre que 10s mitodos de empresa de las aplicaciones del usuario Sean invocados. En terminos sencillos, u n servicio declarativo es u n servicio o acci6n realizado por el contenedor en nuestro nombre.

\.

i . {Como funciona este enfoque? Los contenedores J2EE son, por naturaleza, distribuidos y 10s
componentes de la aplicaci6n son remotos a 10s clientes. Por consiguiente, las solicitudes a 10s componentes de aplicacion y las respuestas procedentes de 10s componentes de aplicaci6n tienen lugar en 10s limites del proceso, plataforma y red. Ademis, puesto que 10s componentes de aplicaci6n son mantenidos en el period0 de ejecuci6n del contenedor, el proceso del contenedor es responsable de recibir las solicitudes y de delegarlas a 10s componentes de aplicaci6n adecuados. Por ejemplo, en el caso del contenedor EJB, el contenedor recibe todas las solicitudes del cliente y las delega a 10s objetos EJB pertinentes implemtados en el contenedor. De un mod0 similar, en el caso de 10s contenedores Web, el contenedor Web recibe las solicitudes http y las delega en 10s servlets y en las piginas Web. El siguiente diagrama representa una visi6n simplificada de esta invocacibn. En esta figura, la interfaz remota es lo que utilizan 10s clientes para comunicarse con el EJB en el contenedor. Observe que el proceso del contenedor maneja todas las solicitudes y respuestas intercambiadas por 10s componentes de la aplicaci6n:
m

a ,

lnterfaz Remota

Este enfoque proporciona al contenedor la capacidad para interponer un nuevo servicio antes de +ransferir una solicitud a1 componente de aplicaci6n. En el caso de transacciones declarativas, el contenedor puede comenzar la transacci6n antes de delegar la solicitud entrante en la implicacidn de I mitodo de empresa y terminar la transacci6n tan pronto como vuelta a1 mitodo.
-

Plataforma J2EE
-iCuil es la ventaja de este enfoque? Podemos interponer nuevos servicios sin cambiar el componente de aplicaci6n. Mis especificamente, esta funci6n nos permite posponer decisiones sobre tales servicios hasta el periodo de ejecucibn, en lugar del tiempo de disefio. En otras palabras, el contenedor puede reforzar selectivamente nuestros componentes basados en el descriptor de desarrollo. Para contenedores EJB, 10s servicios declarativos incluyen transacciones y seguridad. Ambos pueden ser especificados en descriptores de implementaci6n. En el caso de 10s contenedores Web, podemos especificar las funciones de seguridad requeridas para acceder a componentes en las aplicaciones Web.

Otros servicios de contenedor


Los siguientes son algunos de 10s servicios de periodo de ejecucion que proporcionan 10s contenedores: Gesti6n de ciclo de vida de 10s componentes de aplicaci6n Esto conlleva la creation de nuevo ejernplares de componentes de aplicaci6n y su reserva o destrucci6n cuando 10s ejemplares ya no resulten necesarios.
0

Reserva de recursos Los contenedores pueden implementar opcionalmente reserva de recursos, como reserva de objetos o reserva de conexiones. Poblar el espacio de nombre de J N D I basado en el despliegue de nombres asociados a 10s componentes EJB Esta information es proporcionada normalmente en el tiempo de despliegue. Trataremos la implementaci6n en la siguiente secci6n. Poblar el espacio de nombre J N D I con objetos necesarios para utilizar 10s API de servicio del contenedor Algunos de 10s objetos incluyen objetos fuentes de datos para el acceso a bases de datos, colas y factorias de conexi6n de apartados para obtener conexiones con JMS y objetos de transacci6n de usuario para controlar transacciones programlticamente.

Agrupamiento En J2EE, 10s contenedores pueden ser distribuibles. U n contenedor distribuible consiste en un numero de JVM ejecutados en una o mls mlquinas anfitrionas. En esta configuraci6n,los componentes de aplicacion pueden ser desplegados en una serie de JVM. Dependiendo del tip0 de estrategia de equilibrio de carga, el contenedor puede distribuir la carga de solicitudes entrantes a una de estas JVM. La agrupacion es esencial para reforzar la reajustabilidad y disponibilidad de las aplicaciones.

Ahora que ya hemos cubierto la arquitectura de las aplicaciones J2EE, examinemos mis de cerca algunos de las diversas tecnologias incluidas en la plataforma J2EE.

Tecnologias JZEE
Despuks de haber examinado toda la arquitectura de la plataforma J2EE, queremos ahora abarcar la colecci6n de tecnologias que proporcionan 10s rnecanismos que necesitarnos para construir amplias y distribuidas aplicaciones de empresa. Esta gran colecci6n, formada por tecnologias bastante dispares, puede ser clasificada segun su uso:

o Las tecnologias de componentes

Capitulo 1
Estas tecnologias son utilizadas para albergar la mayor parte de la aplicacibn: la 16gica de ernpresa. Existen tres tipos de cornponentes: piginas JSP, senlets y Enterprise JavaBeans; exarninarernos cada uno de ellos a continuation.
0 Las tecnologias de sewicios Estas tecnologias proporcionan 10s cornponentes de la aplicacion con senicios reforzados para que funcionen de un rnodo eficiente. 0 Las tecnologias de comunicaci6n Estas tecnologias, que son en su rnayoria transparentes para el programador de la aplicacion, proporcionan rnecanisrno para la comunicacion entre diferentes partes de la aplicacion, ya Sean locales o remotas.

Exarninemos a continuaci6n la clasificaci6n de API J2EE y sus tecnologias asociadas.

Tecnologias de componentes
C o n cualquier aplicacion, el elernento mis irnportante es el rnodelado de la 16gica de ernpresa necesaria rnediante el uso de componentes o de unidades reusables en el nivel de aplicacion. Anteriormente en este capitulo, hemos descrito un contenedor corno un elernento que alberga el period0 de ejecucion para cornponentes de aplicaci6n, por lo que, aunque el contenedor pueda proveer rnuchos de 10s senicios y gran parte de la infraestructura de cornunicaci6n, es en ultirna instancia responsabilidad del agente de desarrollo crear 10s componentes de aplicacion. Sin embargo, estos cornponentes dependerin de su contenedor para rnuchos senicios, tales corno la gesti6n del ciclo de vida, el enhebrado (threading) y seguridad. Esto nos perrnite concentrarnos en proporcionar la funcionalidad de ernpresa indispensable sin entrar en detalles de sernintica de bajo nivel (nivel contenedor). La plataforrna J2EE ofrece tres tecnologias para el desarrollo de cornponentes. U n aspect0 que debe quedar claro es que la plataforma JZEE n o especifica que una aplicaci6n necesite hacer uso de 10s tres tipos de tecnologias de componentes; en muchos casos, utilizar EJB puede producir u n a sobrecarga.

Componentes Web
Estos cornponentes pueden clasificarse corno cualquier otro cornponente que responda a una solicitud H H T P . Se puede realizar otra distincion rnis profunda basada en el contenedor anfitri6n para 10s cornponentes de la aplicacibn. Como ya hernos visto en este capitulo, 10s dos contenedores bisicos de lado del senidor son el contenedor Web y el contenedor EJB.

Sewlets
Los sewlets son prograrnas de lado del servidor que perrniten a la bgica de aplicacion ser incorporada a1 proceso solicitud-respuesta HTTP. Los senlets proporcionan un rnedio de arnpliar la funcionalidad del senidor Web para adrnitir contenido dinirnico en HTML, XML, u otros lenguajes Web. Con el lanzarniento de J2EE 1.3, la especificaci6n de 10s Servlets ha alcanzado la versi6n 2.3. Trabajarernos con senlets en 10s Capitulos del5 a1 9.

Las Javasewer Pages (JSP) proporcionan un rnodo de incorporar cornponentes en una pigina y de hacer que realicen su funci6n para generar la pigina que seri enviada el cliente eventualrnente. Una pigina JSP

Plataforma J2EE
contiene componentes HTML, cddigo Java y JavaBean. Las piginas JSP son de hecho una extensi6n del modelo de programaci6n del Servlet. Cuando un usuario solicita una pigina JSP, el contenedor Web compila la pigina JSP en un Servlet. El contenedor Web invoca a1 Servlet y devuelve el contenido resultante a1 navegador Web. Una vez que el Servlet ha sido compilado a partir de la pigina JSP, el contenedor Web puede simplemente devolver el servlet sin tener que recopilar cada vez. De este modo, las piginas JSP proporcionan un mecanismo de ensamblaje de piginas dinimico que se beneficia de las diversas ventajas de la plataforma Java. En comparacidn con 10s servlets, que son puro cddigo Java, las piginas JSP son mero documentos basados en texto hasta que el contenedor Web 10s compila en 10s correspondientes servlets. Esto permite una separacidn mis precisa entre la logica de aplicacidn y la 16gica de presentacidn. A su vez, permite a 10s desarrolladores de programas de aplicacidn centrarse en materias de empresa y a 10s disefiadores Web concentrarse en la presentacidn. Con la versidn actual de J2EE, la especificacidn JSP llega a la version 1.2. Los Capitulos 10 a 12 examinan en detalle las piginas JSP. Una arquitectura tipica para una aplicacidn Web que incluya piginas JSP tendria la siguiente estructura:

Navegado

Almacen de Datos

Componentes Enterprise JavaBean


Enterprise JavaBean (EJB) 2.0 es un modelo de componente distribuido para el desarrollo de de un mod0 sencillo, componentes sewros, reaiustables, transaccionales v multi-usuario. Para ex~resarlo son (ideilmente) ;nidades.de software reusables que contienen 16&a de empresa. Del mismo 10s mod0 que las piginas JSP permiten la separacidn entre la 16gica de aplicacidn y la 16gica de presentacidn, 10s EJB permiten la separacidn entre la 16gica de aplicaci6n y 10s servicios a escala del sistema, permitiendo asi a1 agente de desarrollo concentrarse en 10s temas de dominio de empresa y no programar el sistema. Estos objetos de empresa Enterprise Bean adoptan tres formas bisicas (una vez mas, no es necesario implementarlas todas): beans de sesion, beans de entidad y beans dirigidos por mensaje. Examinaremos 10s EJB en accidn en 10s Capitulos 14 a1 19.

GB

Beans de s d o n
Los beans de sesidn se presentan en dos tipos. U n bean de sesi6n de estado es un objeto transitorio utilizado para representar la interaccion de cliente con el sistema; ejecuta la solicitud del cliente en la aplicacion, accediendo a la base de datos, etc. y cuando las operaciones del cliente estin completas es destruido (es decir, existe mientras dura la sesidn del cliente). U n ejemplo de este tip0 de bean es un cliente de aplicacion enviando una serie de solicitudes a una aplicacidn para llevar a cabo un proceso empresarial. En tales casos, un bean de sesi6n de estado puede registrar en estado de la interacci6n entre el cliente y la aplicacidn. La alternativa, un bean de sesion sin estado, no mantiene estado alguno entre las solicitudes del cliente. Generalmente, este tip0 de bean de sesi6n es utilizado para implementar un servicio especifico que no requiere el estado del cliente, por ejemplo, una simple actualizaci6n de base de datos.

Capitulo 1
Beans de entidad U n bean de entidad, por otro lado, es un objeto persistente que modela 10s datos contenidos en el almacen de datos, es decir, es un objeto envoltorio para 10s datos. Por ejemplo, datos sobre una pedido de compra pueden ser modelados utilizando un bean de entidad Purchaseorder que presente una vision agregada de todos 10s datos relacionados con dicho pedido. En comparaci6n con 10s beans de sesi61-1, que pueden ser utilizados por cualquier cliente, muchos clientes pueden acceder a 10s beans de entidad per0 deben mantener una iinica identidad a travks de una clave primaria. De hecho, en la arquitectura del contenedor J2EE podemos elegir entre tener el estado persistente del bean de entidad gestionado por el contenedor o implementarlo "a mano" en el mismo bean. Beans dirigldos por mensaje Los beans dirigidos por mensaje son una clase especial de EJB que no estin destinados a la invocaci6n directa de cliente. El objetivo de 10s beans dirigidos por mensaje es procesar 10s mensajes recibidos via JMS. Los beans dirigidos por mensaje complementan la naturaleza asincrona de JMS proporcionando un medio de procesamiento de mensajes dentro del contenedor EJB. Cuando un cliente de aplicaci6n o una aplicaci6n envia un mensaje via JMS, el contenedor invoca a1 bean dirigido por mensaje adecuado para procesar el mensaje.

e para C o m o ya hemos mencionado en nuestro anilisis anterior, J2EE 1.3 incluye el API JAXP. ~ s t sirve abstraer el parseado XML y 10s API de traducci6n XML. Ademis, hay otros API de Java relacionados con XML que estin siendo desarrollados en la actualidad. Puede encontrar un resumen sobre el tema y mis detalles en la direccidn http://java.sun.com/xml. XML (Extensive Markup Language) influye en c6mo percibimos, procesamos, transportamos y gestionamos datos. XML es un lenguaje autodescriptivo con el que puede enviar datos asi como metadatos. En 10s sistemas de empresa de hoy dia, XML es utilizado para representar datos de empresa tanto en el interior como a travks de aplicaciones. U n o de 10s puntos fuertes de XML es la c o m h utilizaci6n de estos "vocabularios", todos ellos con la misma sintaxis bisica, 10s rnismos analizadores y otras herramientas. Los vocabularios XML compartidos proporcionan mis ficilmente documentos de bkqueda y bases de datos, y un mod0 de intercambiar informaci6n entre diferentes organizaciones y aplicaciones informiticas. Sin embargo, XML puede ser mucho mis que un mecanismo de descripcih:
0 Transformaci6n de

XML

La transformacibn permite al programador copiar un documento XML en una determinada forma basindose en una serie de reglas. Las transformaciones son utilizadas para traducir vocabularios XML similares asi como traducir documentos XML en otros formatos de archivos de base textual como valores delimitados por comas. Este es el tip0 de representaci6n estindar de datos en una empresa.
0 XML y bases de datos

Aunque el modelo de datos XML es inherentemente jerirquico mientras que las bases de datos son esencialmente relacionales (creando algunas dificultades de copia), proporciona un mecanismo de integraci6n de datos existentes en nuevos sistemas. Muchos distribuidores de bases de datos estin afiadiendo en la actualidad funione XML en sus sistemas al reconocer que 10s programadores necesitan recursos para interfacear XML y bases de datos.
0

Comunicaci6n entre servidores

Plataforma J2EE
Las aplicaciones complejas de empresa utilizan a menudo software de servidor distintos ejecutados y distribuidos en diversas tecnologias de procesamiento. XML proporciona una capa de abstracci6n para integrar estos sistemas similares. CML puede obtenerse de un servidor, ser manipulado y despuks enviado a otro servidor de tal modo que pueda comprender la solicitud. Aunque no abarcaremos explicitamente XML en este libro, apareceri cuando creemos varios descriptores de implementaci6n J2EE. Para mis informacidn sobre el uso de XML con Java, puede consultar Profesioonf Java y X M L y Referencia para Programadores Java y XML.

Tecnologias de servicio
Como ya hemos visto, algunos de 10s servicios de J2EE para componentes de aplicaci6n son gestionados por 10s mismo contenedores, permitiendo asi a1 agente de desarrollo concentrarse en la 16gica de empresa. Sin embargo, en ocasiones 10s desarrolladores de programas considerarin necesario invocar ellos mismos programiticamente algunos semicios utilizando algunas de las diversas tecnologias de servicio.

Aunque todos 10s accesos a 10s datos deberian ser accesibles a travks de un h i c o API estindar de la arquitectura de Conector en el futuro, la conectividad de bases de datos es probablemente uno de 10s servicios clave que 10s desarrolladores de programas implementan en su componente de aplicaci6n. El API JDBC (siglas no oficiales para Java Database Connectivity) proporciona a1 agente de desarrollo la capacidad de conectar con sistemas de bases de datos relacionales. Como veremos en el capitulo 4, permite las consultas transaccionales, la recuperacidn y la manipulacidn de datos desde una base de datos que se ajuste a JDBC. Por el momento, merece la pena destacar que J2EE afiade una extensidn a1 nGcleo API JDBC (que esti incorporado en J2SE) para ofrecer caracteristicas avanzadas, como reserva de conexiones y transacciones distribuidas.

Java Transaction API y Servicio


El API Java Transaction (JTA) es un medio para trabajar con transacciones y con transacciones especialmente distribuidas independientes de la implementacidn del gestor de transacciones (elJava Transaction Service (JTS)). En la plataforma J2EE, las transacciones distribuidas estin consideradas generalmente como transacciones controladas por contenedor; por ello, nosotros, como desarrolladores de programas, no deberiamos estar preocupados por las transacciones entre componentes. Sin embargo, el modelo de transaccidn de J2EE es todavia algo limitado y en ocasiones puede que tengamos que realizar el trabajo duro.

La funcidn del API Java Naming and Directory Interface (JNDI) en la plataforma J2EE es doble:
0 En primer lugar,.proporciona 10s medios para ejecutar operaciones estindar en un recurso de servicio directorlo como LDAP, Novel1 Directory Services o Netscape Directory Services. 0 En segundo lugar, una apkaci6n J2EE utiliza J N D I para buscar interfaces utilizadas para crear, entre otras cosas, EJB y conexiones JDBC.

En el pr6ximo capitulo, veremos cdmo utilizar J N D I para acceder a un recurso de servicio directorio.

Capitulo 1
JMS
En el entorno de ernpresa, puede que 10s diversos cornponentes distribuidos no estkn siernpre en constante contact0 entre si. Por lo tanto, es necesario que haya algGn rnecanisrno de envio de datos de rnodo asincrono. El Java Message Service UMS) proporciona exactarnente esta funcionalidad para enviar y recibir rnensajes rnediante el uso de software interrnediario orientado al rnensaje.

JavaMail
JavaMail es un API que puede ser utilizado para abstraer instalaciones para enviar y recibir e-mail. JavaMail se ajusta a 10s protocolos de correo rnis utilizados en Internet corno IMAP4, POP3 y SMTP, per0 en comparaci6n con JMS es rnis lento y rnenos fiable.

Java Conector Architecture


Java Connector Architecture UCA), presentado en la versi6n 1.3, es un rnedio estandarizado por el que las aplicaciones J2EE pueden acceder a una variedad de aplicaciones legadas, norrnalrnente sisternas Enterprise Resource Planning (ERP) corno SAP R/3 y Peoplesoft. La especificaci6n del Conector define una sencilla arquitectura en la que 10s distribuidores de servidores de aplicaci6n J2EE y sistemas legados colaboran para producir cornponentes "plug-and-play" que nos perrnitan acceder al sisterna legado sin tener que tener conocirnientos rnuy especificos sobre c6rno trabajar con 61.

JAAS
El servicio Java Authentication a n d Authorization Service proporciona un rnedio para conceder perrnisos basado en q u i h ejecuta el c6digo. JAAS utiliza una arquitectura conectable de rn6dulos de autentificaci6n de mod0 que el usuario pueda introducir rn6dulos basados en diferentes irnplernentaciones de autentificacibn, corno Kerberos o PKI (Public Key Infrastructure).

Tecnologias de comunicacion
El Gltirno grupo de tecnologias esti forrnado por las tecnologias que proporcionan 10s rnedios para 10s diversos cornponentes y servicios de la aplicaci6n J2EE para su cornunicaci6n entre si; una aplicaci6n distribuida seria bastante ineficaz si estas tecnologias no proporcionaran el "pegarnento" para unir todos 10s elernentos.

Protocolos de Internet
Mientras hablarnos de aplicaciones de n-niveles en este libro, nuestro cliente seri rnuy a menudo un navegador potencialrnente situado en cualquier lugar del mundo. Las solicitudes de un cliente y las respuestas de un servidor se cornunican a travks de tres protocolos principales. HTTP H T T P o Hypertext Transfer Protocol es un protocolo genCrico, sin estado, de nivel aplicaci6n, que tiene muchos usos rnis alli de sus sencillas capacidades corno hipertexto. Funciona sobre una base solicitud/ respuesta. U n cliente envia una solicitud al servidor en forrna de mktodo de solicitud, URI (Uniform Resource Identifier) y versi6n de protocolo, seguido por un rnensaje tipo MIME que contiene rnodificadores de solicitud, inforrnaci6n del cliente y posible contenido de cuerpo en una conexi6n con un

Plataforma J2EE
senidor. El servidor a su vez responde con una linea de estado seguida por un mensaje de tipo MIME que contiene informaci6n del servidor, informaci6n meta de entidad y posible contenido entidad-cuerpo.

T C P (Transmisi6n Control P ~ o t o c o l ) sobre I P (Internet Protocol) son realmente dos protocolos distintos, que se combinan normalmente en una unica entidad. I P es el protocolo responsable de asegurar que 10s datos son recibidos en ambos extremos de la comunicaci6n a traves de Internet. Cuando tecleamos la direcci6n de un sitio Web en nuestro navegador, el protocolo I P certifica nuestras solicitudes y qu el cumplimiento de esas solicitudes Ilegan hasta su destino. Para mayor eficiencia, 10s datos que son enviados y recibidos entre un cliente y un servidor Web son descompuestos en varias piezas o paquetes. N o todos estos paquetes tienen que tomar la misma ruta a1 ser enviados entre el cliente y el servidor Web. T C P es el protocolo que registra 10s paquetes y certifica que son reunidos en el mismo orden en el que fueron divididos y sin errores. Por lo tanto, T C P y I P trabajan juntos para mover datos en Internet. Por este motivo, casi siempre veremos estos dos protocolos combinados en TCP/IP.

Secure Sockets Layer (SSL) utiliza la criptografia para cifrar el flujo de informaci6n entre el cliente y el servidor. Tambien proporciona un medio para que ambas partes puedan autentificarse entre si. Secure http (HTTPS) se distingue normalmente del http corriente sin cifrar a1 ser servido en diferente numero de puerto (443, por defecto).

Protocolos de objeto remoto


En aplicaciones donde 10s componentes se distribuyen normalmente en diferentes niveles y servidores, se requieren algunos mecanismos para utilizar 10s componentes de forma remota, preferiblemente dejando que el cliente ignore que el componente no es local respecto a si mismo.
RMl y RMI-IIOP

Remote Meted Invocation (RMI) es uno de 10s mecanismos primarios en las aplicaciones de objetos distribuidos. Nos permite utilizar interfaces para definir objetos remotos. Podemos entonces llamar a metodos en estos objetos remotos como si fueran locales. Los mecanismos de transporte utilizados dependen de cada implementaci6n. Por ejemplo, Sun utiliza Java Remote Meted Protocol (JRMP) sobre TCP/IP, pero otras implementaciones, como BEA WebLogic, por ejemplo, tienen su propio protocolo. RMI-IIOP es una extensi6n de RMI per0 en I I O P (Inter.-ORB Protocol), que nos permite definir una interfaz remota a cualquier objeto remoto que pueda ser implementado en cualquier lenguaje que se ajuste a la asociaci6n O M G y ORB. En el capitulo 3, examinaremos con detenimiento c6mo escribir aplicaciones distribuidas con RMI.

Mediante el uso de JavaIDL, un cliente Java puede invocar llamadas de metodo en objetos CORBA. Estos objetos CORBA no necesitan ser escritos en Java sino implementar meramente una interfaz IDL definida.

Desarrollo de aplicaciones JZEE


La especificacidn J2EE concreta 10s siguientes pasos en el proceso de desarrollo y despliegue de aplicaciones.

I. Desarrollo de componentes de aplicaci6n

Durante este paso modelamos las reglas de la empresa en forma de componentes de aplicacion.
2.

Composicion de componentes de aplicaci6n en modulos En este paso, 10s componentes de aplicacion son empaquetados en m6dulos. Esta fase tambikn conlleva proporcionar descriptores de implementaci6n para cada m6dulo. Este paso integra mfiltiples m6dulos en aplicaciones J2EE. Requiere ensamblar uno o mis m6dulos en una aplicaci6n J2EE y facilitarle 10s archivos de descriptor.

3. Composici6n de m6dulos e n aplicaciones

4.

Despliegue de aplicaci6n En el paso final, la aplicaci6n empaquetada es realmente desplegada e instalada en el sewidor(es) de aplicaci6n de la plataforma J2EE.

La plataforma JZEE especifica mdtiples niveles para empaquetado, adaptacidn, e instalacidn. El empaquetado es el proceso de componer aplicaciones a partir de componentes de aplicaciones. J2EE especifica u n plan de empaquetado de tres niveles para componer componentes en aplicaciones. Estos son: componentes de aplicacidn, mo'dulos y aplicaciones.
iCuLl es el prop6sito de estas fases para el desarrollo e implementaci6n de aplicaciones? En J2EE, la arquitectura de aplicaciones emeieza con la descomposici6n de la aplicaci6n en m6dulos y de 10s m6dulos en componentes de aplicacion. Este es un proceso descendente hacia la construcci6n de 10s bloques de construcci6n mis pequefios. La noci6n de empaquetado y despliegue de aplicaci6n en niveles mfiltiples intenta conseguir este prop6sito. En este proceso, componemos componentes de aplicaci6n de grano fino en m6dulos y despuks 10s modulos en aplicaciones.

Funciones de desarrollo e implernentacion de aplicaciones


Antes de pasar a examinar detenidamente el proceso de desarrollo e irnplementaci611, desvikmonos momentineamente para analizar quikn deberia hacer quk. La especificaci6n J2EE, ademis de definir un - proceso, tambikn define una serie de funciones en el desarrollo de aplicaciones J2EE:
0

Proveedor del product0 J2EE El Proveedor del prodycto J2EE proporciona la plataforma base J2EE sobre la cual desarrollamos nuestras aplicaciones. Este seri nuestro distribuidor de sewidor que implementa la arquitectura del contenedor y 10s API son definidos por la especificaci6n JZEE.

CI Proveedor de componente de aplicaci6n Es esencialmente el agente de desarrollo de la aplicaci6n quien crea la funcionalidad de la aplicaci6n, aunque es posible subdividir la funci6n en ireas especificas de conocimientos tkcnicos, por ejemplo, agente de desarrollo de Web, agente de desarrollo de EJB, etc.
0

Ensamblador de aplicaciones C o m o veremos en breve, el ensamblador de aplicaciones toma 10s componentes de aplicaci6n y 10s empaqueta a travks de una serie de m6dulos y archivos de descriptores de mod0 que puedan ser implementados a 10s sewidores de producci6n. Desplegador El desplegador toma la aplicaci6n empaquetada, la instala y la configura para el entorno particular de operaci6n en el que seri ejecutada la aplicacibn.

Plataforma J2EE
0

Administrador del sistema El Administrador del sistema es responsable de mantener y administrar la aplicaci6n una vez que ya ha sido implernentada. Proveedor de herramientas El Proveedor de Herramientas proporciona las herramientas que pueden ser de uso en el desarrollo e implernentaci6n de 10s componentes de aplicaci6n.

Observe que esta clasificacio'n de funciones puede ajustarse o no a su aplicacio'n espec$ca y esta clas2ficacidn sdlo deberia considerarse una configuracidn tt'pica que puede servir corno guia.

,Desarrollo de componentes de aplicacion


En J2EE, el proceso de desarrollo cornienza con el disefio y el desarrollo de componentes de aplicaci6n. La mayor parte de este libro versari sobre este tema, por lo que no es necesario que profundicemos en ello aqui.

;Composition de componentes de aplicacion en


modulos
U n m6dulo es utilizado para ernpaquetar uno o rnis cornponentes de aplicaci6n relacionados del misrno tipo. Ademis de 10s cornponentes de aplicaci6n, cada rn6dulo incluye un descriptor de irnplementaci6n que describe la estructura del rn6dulo. Hay tres tipos de rn6dulos en J2EE:
A .

M6dulos Web U n m6dulo Web es una unidad desplegable compuesta de Senlets de Java, piginas JSP, bibiliotecas de etiquetas, archivos JAR de biblioteca, docurnentos HTML/XML y otros recursos publicos tales corno irnigenes, archivos de clase applet, etc. U n rn6dulo Web es ernpaquetado en un archivo Web Archive, tarnbih conocido corno archivo WAR. U n archivo WAR es similar a un archivo JAR; la diferencia radica en que el archivo WAR contiene un directorio WEB- I N F con la descripci6n de irnplernentaci6n contenida en un archivo Web. x m l . Conoceremos mis detalles de 10s rnbdulos Web y su empaquetado en pr6xirnos capitulos. Modulos EJB U n rn6dulo EJB es una unidad desplegable cornupuesta de un EJB, asociado a archivos JAR de biblioteca y recursos. Los rn6dulos EJB estin ernpaquetados en archivos JAR, con un descriptor F~ del - archivo JAR. de implernentaci6n (e j b- j a r .x m l ) en el d i r e c t o r i o ~ I~N~ M6dulos Java U n rn6dulo Java es un grupo de clases de cliente Java empaquetados en archivos JAR. El descriptor de irnplernentaci6n para un rn6dulo Java es un archivo a p p l i c a t i o n - c l i e n t .x m l .

'

Composicion de modulos en aplicaciones


El nivel rnis alto de ernpaquetado esti en forrna de aplicaciones. Cada aplicaci6n J2EE es una unidad independiente de c6digo dentro de un caj6n virtual propio. Norrnalrnente, 10s contenedores J2EE cargan cada aplicaci6n utilizando un cargador de clase diferente de rnodo que cada aplicaci6n queda aislada del

Capitulo 1
resto. El objetivo de este aislamiento es permitir a las multiples aplicaciones JZEE coexistir en un contenedor JZEE. Una aplicaci6n JZEE consiste en uno o mds mddulos compuestos en un archivo Enterprise Archive (EAR). U n archivo EAR es similar a un archivo "TAR; . la diferencia es que el primer0 contiene un archivo a p p l i c a t i o n . xml (situado en el d i r e c t o r i o ~ INF) ~ ~ ~ que - describe la aplicacibn:

iCudl es la funcidn de 10s mdtiples archivos de descriptor en la figura anterior? Los componentes de aplicaci6n de menor tamafio pueden ser adaptados mientras son integrados en m6dulos. Esto requiere el uso de un descriptor de implementacidn en un mddulo. Sin embargo, no toda la informacidn relacionada con la implementaci6n final sobre una plataforma JZEE estard disponible en el momento del ensamblado de m6dulos. Ademis, necesitamos medios para especificar quk m6dulos componen la aplicacidn. La ventaja de esta estructura es que permite la reutilizaci6n a diferentes niveles. Los componentes de aplicaci6n pueden ser reusados en miiltiples mddulos Web. Por ejemplo, 10s componentes Web relacionados con el registro de usuario pueden ser empaquetados en diferentes m6dulos Web responsables de 10s servicios de pedido y de compra on-line. De un mod0 similar, 10s mddulos pueden ser reusados en multiples aplicaciones de mod0 que un m6dulo EJB para la gesti6n del carro de la compra n o necesita ser restringido a una Gnica apkaci6n, sino que puede ser empaquetado en mdtiples aplicaciones de comercio on-line.

Sin estos medios de empaquetado reusables, el objetivo de la reutilizacidn de componentes d o se alcanzaria parcialmente. A1 definir la estructura anterior, J2EE permite una reutilizacidn mris refinada de 10s componentes de aplicacidn.

Implementation de la aplicacion
Finalmente, la implementaci6n de aplicacidn es el proceso de instalacidn y adaptaci6n de 10s m6dulos empaquetados sobre la plataforma JZEE. Este proceso conlleva dos pasos:
0

Preparar la aplicaci6n para su instalaci6n sobre un servidor de aplicacidn JZEE. Esto conlleva copiar 10s archivos EAR sobre el servidor de aplicaci6n, generando clases de implementaci6n adicionales con la ayuda del contenedor, e instalar finalmente la aplicaci6n sobre el servidor.

Plataforma J2EE
O Configurar la aplicaci6n con la inforrnaci6n de la aplicaci6n especifica del senidor. U n ejernplo seria la creacion de fuentes de datos y factorias de conexiones, ya que la creaci6n real de estos objetos es especifica del senidor de aplicaci6n.

En estos rnomentos deberia tener una idea rnis cornpleta de la tipologia del paisaje J2EE. En particular, hernos visto c6rno J2EE arnplia la arquitectura multi-nivel tradicional de procesarniento distribuido para incluir el concept0 de contenedores. Hernos exarninado las partes constituyentes de esta arquitectura de contenedor, con relaci6n a:

O El contrato de cornponentes O Senicios de contenedor

o Senicios declarativos
O Otras instalaciones de periodo de ejecuci6n
Los siguientes son 10s puntos clave de este examen:
O J2EE es una arquitectura centrada en el contenedor. U n contenedor en rnis que un simple periodo

de ejecuci6n: proporciona varios niveles de abstracci6n. En pr6xirnos capitulos, exarninaremos como estas abstracciones sirnplifican la irnpelernentaci6n de aplicaciones.
O J2EE reconoce la necesidad de cornponer 10s cornponentes en rn6dulos y rnodulos en aplicaciones.

Es un intento de normalizar la reutilizaci6n de cornponentes de aplicaci6n y m6dulos.

O J2EE representa un enfoque rnuy intuitive para construir aplicaciones. Mientras que el proceso de disefio es descendente, el proceso de irnplernentaci6n es ascendente y es un proceso de composici6n, que cornpone rn6dulos a partir de cornponentes y aplicaciones a partir de rn6dulos.
Despues de concluir nuestro anilisis introductorio de la perspectiva de J2EE de la prograrnaci6n Java de lado senidor, cornenzarernos un recorrido detallado examinando de cerca la b6squeda de senicios utilizando JNDI.

Servicios de directorio y JNDI


Las interfaces J N D I (Java Naming and Directory Services Interfaces) estin disefiadas para simplificar el acceso a la infraestructura de directorio utilizada en el desarrollo de aplicaciones de redes avanzadas. Los directorios son un tip0 especial de bases de datos que proporcionan ripido acceso a sus almacenes de datos. Las bases de datos son consideradas normalmente el modelo relational de almacCn de datos por excelencia, como Oracle, Microsoft SQL Server, etc. En contraste con esto, una base de datos de directorio almacena informaci6n de forma jerirquica y optimizada para la lectura. Normalmente, hemos tenido que utilizar diferentes API para acceder a distintos servicios de directorio, como el servicio de informaci6n de Sun Network Information Service (NIS) o Lightweight Directory Access Protocol (LDPA). Sin embargo, J N D I proporciona un API estindar para acceder a cualquier tipo de directorio. J N D I tambiCn nos permite almacenar y recuperar objetos Java en la red, por ejemplo, del servidor de aplicaci6n adaptado a J2EE, como BEA WebLogic. En este capitulo, responderemos a las siguientes preguntas:
0 0 0

iQuC es un servicio de directorio? iQue distingue a J N D I de un API de directorio tradicional! iQuC es LDPA y c6mo lo utilizamos para trabajar con un servicio de directorio?

Ademis, examinando algunos programas de ejemplo, demostraremos de primera mano las aplicaciones pricticas del uso de J N D I para gestionar la informaci6n del directorio.

Servicios de designacion y de directorio


"La red es el ordenador" es una frase que Sun Microsystems ha utilizado para vender sus productos de software y hardware. Es tambikn el dogma de la exitosa programaci6n Java. Una de las razones por las que Java es tan popular es porque ha conseguido que la programaci6n de redes sea mis ficil que con otros

Capitulo 2
lenguajes, como con C. Esto se debe a que Java es mucho mis que una especificaci6n de lenguaje. Java incorporada 10s sistemas de redes en su API central, mientras que lenguajes tales como C requieren una bibilioteca externa para reproducir la misma funcionalidad. Las funciones de red que incorpora Java garantiza el Cxito de este leguaje debido a que el numero de ordenadores conectados que utilizan 10s protocolos estindar de Internet ha crecido a un ritmo excepcional. Los dispositivos se situan normalmente en una red para facilitar su gesti61-1, ahorrando tiempo y, a su vez, dinero. Por ejemplo, en un complejo de edificios un sistema medioambiental en red puede informar a un servidor central. Este servidor puede informar sobre el estado de todos 10s sistemas de aire acondicionado y termostatos de 10s diferentes edificios a 10s ingenieros medioambientales. Desde esta fuente central, 10s ingenieros pueden saber cuindo una unidad se esti sobrecalentando, o cuindo deben planificar 10s servicios de mantenimiento. Si el sistema medioambiental no estuviera conectado en red, 10s miembros del equipo tendrian que comprobar cada dispositivo de forma individual, lo que supondria una tarea laboriosa y larga cuando se tratara de docenas de edificios. Por supuesto, aunque tenemos dispositivos en red y un gran lenguaje de desarrollo como Java, puede resultar dificil combinarlos de un mod0 efectivo. Siempre que se afiade un dispositivo a la red, la informaci6n de configuraci6n debe ser adaptada. Esta informaci6n de configuraci6n incluye propiedades tales como una direcci6n IP, un nombre de dominio, las prestaciones de cada dispositivo de red y 10s privilegios de usuario para cada dispositivo. Esta informaci6n esta disponible normalmente para el dispositivo mismo, per0 no siempre lo esti para el mundo exterior. Por ejemplo, cuando establecemos una nueva estaci6n de trabajo en la red, con frecuencia necesitamos configurarla para utilizar una impresora de red especifica. A menudo no es posible descubrir las funciones de las impresoras que estin disponibles, porque las impresoras no ofrecen esta informaci6n. Utilizando el servicio de directorio y Java, las prestaciones y la configuraci6n de la impresora pueden ser incorporadas a la red. Los dispositivos pueden consultar a la impresora para descubrir, por ejemplo, si puede imprimir en color. Los disefiadores del entorno J2EE y sus API comprenden estos problemas. Por este motivo, el API Java Naming and Directory Interfaces (JNDI) se convirti6 en una parte fundamental de J2EE. Descubriri que pricticamente todas las aplicaciones J2EE utilizan J N D I en algun momento. Para entender J N D I , necesitamos una comprensi6n bisica de lo que es un servicio de designaci6n y directorio. TambiCn necesitamos comprender por quC es importante que J N D I proporcione una interfaz normalizada para estos servicios.

Servicios de designacion
Un servicio de designaci6n es un servicio que permite la creaci6n de un nombre estdndar para un conjunto determinado de datos.
En Internet, cada host tiene un nombre de dominio completo y cualificado, Fully Qualified Domain Name (FQDN), como www.wrox.com o www.coe.unt.edu. U n F Q D N se construye a partir de un hostname, cero o mis nombres de subdominio, y un nombre de dominio. Por ejemplo:
-

Hostname
www.coe.unt.edu www.wrox.com www.p2p.wrox.com www www www

Subdominio
coe

Dominio

P ~ P

Servicios de directorio y JNDl


Cada F Q D N es unico, lo que significa que s61o se permite un www.wrox.com y un www.coe.unt.edu. Utilizando nombres de subdominios y de dominios, 10s sistemas que comparten el mismo nombre de anfitri6n siguen considedndose entidades separadas. Por ejemplo, www.p2p.wrox.com es diferente de www.wrox.com. En este caso, el subdominio p2p.wrox.com esti realmente por debajo del dominio raiz de wrox.com obteniendo su nombre de espacio hnico.

Servicios de directorio
Un servicio de directorio es un tip0 especial de base de datos optimizado para acceso de lectura utilizando varias ticnicas de indizaci6n, almacenamiento en memoria y acceso a disco. La informaci6n contenida en un servicio de directorio se describe utilizando un modelo de informaci6n jerirquica.
El modelo de inforrnacion jerirquica que emplean 10s servicios de directorio contrasta con el modelo de informaci6n relacional empleado por las bases de datos, como Oracle y Microsoft SQL Server, que estin creadas para manejar transacciones. Una operaci6n sblo se realiza con kxito si un conjunto de operaciones rnis pequeiias son realizadas con kxito. U n servicio de directorio tambikn es diseiiado normalmente de mod0 que pueda ser distribuido y copiado. U n s e ~ c i de o directorio siempre t e n d d un servicio de designacibn, per0 un servicio de designaci6n no siempre tiene un servicio de directorio. U n ejemplo sencillo de un servicio de directorio es un listin telef6nico. U n listin telef6nico permite a1 usuario encontrar ripidamente el nhmero de tekfono de una persona, siempre que el usuario conozca el nombre de la persona cuyo numero esti buscando. Si nos quedamos un momento con este ejemplo, podemos subrayar 10s beneficios de 10s servicios de directorio en red. Es decir, un servicio de directorio s61o es tan Gtil como la actualidad de su informacidn y la eficacia de realizar una busqueda. Los recursos estiticos, tales como copias fisicas de listines telef6nicos, guias de televisi6n, etc., se tornan obsoletas poco despuks de ser publicadas y norrnalmente s610 ofrecen un medio de acceso (por ejernplo, rnediante el "apellido" en el caso de un listin telef6nico). U n servicio de directorio electr6nic0, por otro lado, es claramente rnis dinimico y permite mucha rnis flexibilidad de bhsqueda. La informaci6n que se recibe probablemente estk actualizada en el momento de la

consults.
Existen rnuchos servicios de directorio (y seudo-directorio) en uso en las redes en la actualidad. U n servicio de directorio muy utilizado es el Domain Naming Service (DNS) utilizado en Internet. D N S acepta u n F Q D N y devuelve una direccidn IP. Este servicio es esencial para Internet ya que una comunicaci6n eficaz entre dos ordenadores confia en que cada sistema conoce la direcci6n I P del otro. Las direcciones I P consisten en la actualidad en 32 bit, por ejemplo 198.137.24 0.92, mientras que un hostname toma la forrna www.wrox.com. Los ordenadores estin acostumbrados a tratar con nhmeros, per0 la mayoria de 10s humanos son rnis diestros a la hora de recordar nombres (es mucho rnis ficil recordar www.wrox.com que recordar 198.137.24 0. 92). El sistema D N S es un ejemplo de un servicio de directorio altamente especializado. Cuando introducimos el hostname en un navegador, el ordenador obtiene la direcci6n I P del servidor via DNS. Analizaremos rnis detenidamente el lado prictico del sistema DNS con un ejernplo en partes posteriores del capitulo.

DNS nos proporciona en realidad algo ma's que direcciones ZP. Por ejemplo, 10s nombres de las ma'quinas responsables de encaminamiento de correo, pero sigue siendo rnuy especializado en sus funciones.

Las organizaciones a rnenudo utilizan uno o rnis de 10s siguientes servicios de directorio de prop6sito general:
0

Novell Directory Services (NDS)

0 Network Information Services (NIS/NIS+) 0

Active Directory Services (ADS)

0 Windows N T Domains

Aunque el Semicio N T Domains no es un verdadero servicio de directorio, son muchos 10s que intentan utilizarlo corno tal.
Cada uno de estos servicios de directorio proporciona rnis inforrnaci6n que la simple copia del nornbre de I P que obtenernos de DNS. Cada servicio de directorio tarnbikn perrnite que inforrnaci6n sobre usuarios sea alrnacenada (nornbres de usuario y contrasefias), grupos de usuario (para control de acceso) y ordenadores (ethernet y direcciones IP). NDS y ADS albergan rnis funciones (corno la localizaci6n de irnpresoras de red y software) que NIS o N T Domains. Corno hay tantos servicios de directorio (cada uno con su protocolo) y corno tenernos tantos sisternas en nuestras redes, han surgido algunos problernas irnportantes. En esencia, se reducen a dos ternas clave:
0 Mantener un registro de usuarios. 0 Mantener un registro de recursos de red corno ordenadores e irnpresoras.

U n rnarco particularrnente dificil seria aquel en el que 10s usuarios necesitarian acceder a:
0 U n sisterna Novell (que utilice NDS) para uso cornGn de archivos e irnpresi6n. 0 0

Una cuenta en una unidad Windows N T para ejecutar Microsoft Office. Una cuenta en una unidad U N ~ X (utilizando NIS) para hacer uso del e-rnail y publicar piginas Web.

Por desgracia para 10s gestores de red, ninguno de estos servicios de directorio puede interactuar ficilrnente entre si, lo que dificulta bastante a1 desarrollador de aplicaciones tradicionales interactuar con varios servicios de directorio diferentes. Corno consecuencia, 10s usuarios suelen tener a1 final diferentes nornbres de usuario y contrasefias para cada sisterna. Si un usuario se da de baja, puede resultar dificil asegurar que todas sus cuentas son elirninadas. Los vacios de seguridad tienen h g a r en forrna de cuentas "huerfanas", que son cuentas que pertenecen a usuarios que ya no estin en una organizaci6r1, aunque todavia tienen libre acceso a 10s sisternas. Una soluci6n a estos problernas es utilizar JNDI, que proporciona un API estindar para una variedad de servicios de directorio. Sin embargo, debido a que no todo el rnundo utiliza Java, es necesario que exista otro rnodo de facilitar la cornunicaci6n de inforrnaci6n de directorio entre sisternas.

E L protocolo Lightweight Directory Access Protocol (LDAP) fue desarrollado a principios de 10s afios noventa corno protocolo de directorio estindar. LDAP es ahora probablernente el protocolo de directorio rnis popular y, debido a que J N D I puede acceder a LDAP, invertirernos algGn tiernpo en aprender corno aprovechar LDAP para rnejorar las aplicaciones Java con JNDI.

LDAP puede remontar su origen a1 protocolo X.500 (tambibn conocido corno "Heavy" Directory Access Protocol), que estaba originalmente basado en 10s protocolos de red O S I (un primer "competidor" de 10s protocolos de Internet).

Servicios de directorio y JNDl


El usuario interactuari a rnenudo con un servidor que ha sido especificarnente construido para LDAP, corno es el caso de iPlanet Directory Server. Sin embargo, LDAP puede ser enfrentado a cualquier tip0 de alrnactn de datos. Por ello, 10s servicios de directorio de mayor aceptaci6n cuentan en la actualidad con un frontal LDAP de algdn tipo que incluye NIS, NDS, Active Directory e incluso Windows N T Domains. LDAP define c6mo 10s clientes deben acceder a 10s datos e n el servidor. Sin embargo, n o especifica c6mo deben ser almacenados 10s datos en el sewidor.

Los datos en LDAP estin organizados en forrna de irbol jerirquico, llarnado Directory Information Tree (DIT), o Arbol de Inforrnaci6n de Directorio. Cada "hoja" del DIT es conocida corno una entrada y la prirnera entrada en un DIT se denornina entrada raiz. Una entrada cornprende un Distinguished Name (DN), o Nornbre Diferenciado, y cualquier nurnero de pares de valor atributo. El D N es el nornbre de una entrada y debe ser unico, igual que la clave Bnica de una tabla de base de datos relational. U n D N rnuestra c6rno la entrada esta relacionada con el resto del DIT, igual que el nornbre de la ruta de un archivo rnuestra c6rno tste se relaciona con el resto de 10s archivos de un sisterna. La ruta hacia un archivo en un sisterna se lee de izquierda a derecha a la hora de leer desde la raiz a1 archivo. U n D N se lee de derecha a izquierda a la hora de leer desde la raiz a la entrada, por ejernplo:

La parte situada a la izquierda de un D N se denornina Relative Distinguished Name (RDN), o Nornbre Diferenciado Relativo, y esti forrnado por un par de valor atributo que se encuentra en la entrada. El R D N en este ejernplo s e r i a u i d = s c a r t e r . Los atributos LDAP a rnenudo utilizan rnnernottcnicas corno nornbres. ~ s t o son s algunos de 10s atributos LDAP rnis cornunes:

Atributo LDAP
Cn
Sn

Definici6n Nornbre cornun Apellido Primer nornbre I D de usuario Nornbre Diferenciado Direcci6n de e-mail

Givenname Uid Dn mail

Los atributos pueden tener uno o rnis valores. Por ejernplo, un usuario puede tener rnis de una direcci6n de e-mail, por lo que necesitarin rnis de un valor para su atributo m a i l . Los valores de atributo pueden ser texto o datos binarios y se hace referencia a ellos en paresnornbre/valor. Hay tarnbitn un atributo especial llarnadoob j e c t c l a s s . El atributoob j e c t c l a s s de una entrada especifica q u t atributos son necesarios y qut atributos estin perrnitidos en una entrada en particular. A1 igual que 10s objetos en Java, las clases de objeto en LDAP pueden ser arnpliadas. Cuando una clase de objeto es arnpliada para una entrada en particular, la clase de objeto rnantiene 10s atributos existentes, per0 10s nuevos atributos pueden ser especificados.

Capitulo 2
~ s t es e un ejemplo de entrada LDAP (sobre las que hablaremos rnis adelante en este capitulo) representado en el formato LDAP Data Interchange Format (LDIF), que es el mod0 mis comlin de mostrar 10s datos LDAP en un formato legible:
d n : uid=scarter, ou=People, o=fedup.com cn: S a m Carter sn: Carter givenname: S a m o b j ectclass: t o p objectclass: p e r s o n objectclass: organizationalPerson objectclass: inetOrgPerson o u : Accounting o u : People 1: Sunnyvale uid: scarter mail: scarterFfedup.com telephonenumber: t1 408 555 4798 facsimiletelephonenumber: t1 408 555 9751 roomnumber: 4612

Los atributos tambikn tienen reglas de concordancia. Estas reglas indican a1 servidor como decidir si una entrada concreta concuerda o no con una determinada consulta. Las posibles reglas de concordancia son estas: Regla de concordancia Significado El atributo esti en forma de un Nombre Diferenciado El atributo puede concordar si el valor de la consulta es igual a1 valor del atributo, con independencia del caso El atributo puede concordar si el valor de la consulta es igual a1 valor del atributo incluido el caso Es lo mismo que CIS except0 que caracteres como "-" y son ignorados a la hora de determinar la concordancia

DN
Case-Insensitive String (CIS) Case-Sensitive String (CSS)

Telephone Integer Binary

"0"

La concordancia de atributo es determinada utilizando s61o nGmeros El atributo concuerda si el valor de la consulta y el valor del atributo son 10s mismos valores binarios (por ejemplo, consultar una base de datos LDAP para buscar una foto concreta)

La definici6n de atributos, las reglas de concordancia de atributos y la relaci6n entre clases de objetos y atributos estin definidas en el esquema del servidor. U n servidor contiene un esquema predefinido pero, siempre que el servidor se ajuste a1 protocolo LDAP v3 tal y como se define en RFC 2251 (http:l/ www.ietf.org/rfc/rfc2251.txt), el esquema puede ser ampliado para incluir nuevos atributos y clases de objeto. Los servidores LDAP tienen otras ventajas. Admiten referentes (apuntadores hacia otros directorios LDAP en 10s que residen datos), de mod0 que un Gnico servidor LDAP puede buscar millones de entradas a partir de la consulta de un solo cliente y 10s datos LDAP pueden ser replicados para mejorar la fiabilidad y aumentar la velocidad. LDAP cuenta tambikn con un modelo de seguridad muy fuerte que utiliza ACL para proteger 10s datos que se encuentran en el interior del servidor y ajustindose a 10s protocolos de Secure Socket Layers (SSL), Transport Layer Security (TLS) y Simple Authentication and Security Layer (SASL). L D A P estd teniendo una creciente aceptacio'n como servicio de directorio central para sistemas de red. Para mds informaci6n acerca de L D A P deberia consultar Implementando LDAP por Mark Wilcox, de Wrox Press, ISBN 1-861002-21-1.

Servicios de directorio y JNDI

Introduction de JNDI
Aunque LDAP esta creciendo en popularidad y en uso, le queda todavia mucho camino que recorrer hasta llegar a ser omnipresente. Otros servicios de directorio tales como NIS son todavia muy utilizados y es posible que sigan sikndolo durante mucho tiempo todavia. O t r o aspect0 es que las aplicaciones de empresa necesitan con frecuencia ajustarse a las normas de procesamiento distribuido existentes, tales como C o m m o n Object Request Broker Architecture (CORBA), que se utiliza mucho en muchas grandes organizaciones para permitir que diferentes tipos de aplicaciones interacthen entre si. CORBA es una arquitectura independiente del lenguaje y de la plataforma utilizada que permite la programacion de aplicacionesdistribuidas, en la que una aplicaci6n en una miquina puede acceder a una funcion de una aplicacion diferente situada en una miquina diferente como si estuviera llamando una funcion interna. CORBA utiliza el servicio COSNaming (CORBA Object Service) para definir la posicion de 10s objetos disponibles. Para superar estas dificultades, se ha creado un API estindar de Java para que interactfie con 10s servicios de designation y directorio. Este API es anilogo a1 mod0 en el que 10s desarrolladores de programas utilizan JDBC para interactuar con todo tipo de bases de datos. JNDI es fundamental para el desarrollo a largo plazo de Java, en particular de la iniciativa Enterprise JavaBeans (EJB). El significado de EJB para J2EE queda reflejado en el hecho de que una larga proporci6n de este libro esti dedicado a EJB. Empezando por el capitulo 16, veremos de primera mano la importancia de JNDI para la funcionalidad de EJB. U n componente clave de la tecnologia EJB es la capacidad para almacenar y recuperar objetos en la red. U n servicio de directorio va a ser el almackn primario de datos para objetos estables Java, que son recuperados de la red en mis ocasiones de las que son almacenados. Esto ocurre porque, cuando 10s objetos son cargados de la red, queremos poder localizarlos ripidamente y un servicio de directorio nos permite una ripida busqueda y recuperation de datos. Estos datos pueden ser cualquier cosa, incluido un registro de un usuario particular de datos binarios, como un objeto Java serializado. Los siguientes diagramas le ayudarin a ilustrar la relacion entre 10s servicios de directorio, JNDI y LDAP. El primer diagrama muestra la relacion entre un cliente y una variedad de servicios de directorio. Cada servicio de directorio requiere su propio API, que afiade complejidad y sobrecarga de codigo para nuestra aplicaci6n de cliente:

API NIS

API NDS

Dorninios NT

Este diagrama puede simplificarse utilizandoJND1. Hay todavia miltiples servidores y multiples API por debajo, per0 para el creador de la aplicacion aparece como un 6nico API:

Capitulo 2

Cliente

JNDI

Proveedor de Sewicio LDAP

Proveedor de Sew~c~ NDS o

API LDAP
?

API NDS
?

Sewldor LDAP

Sewidor NDS

Asi, como desarrolladores de programas, nos resulta mis ficil crear aplicaciones de red porque podemos concentrarnos en un finico API. Sin embargo, todavia tenemos que enfrentarnos a problemas potenciales porque no todos 10s proveedores de servicios J N D I estdn creados del mismo modo. Los proveedores de servicios en terminologia J N D I son 10s dispositivos que permiten la interaccidn con diferentes servicios de directorio. Cada servicio de directorio es claramente diferente (nombran sus entradas de forma diferente y tienen diferentes capacidades), por lo que 10s desarrolladores de programas todavia construyen aplicaciones que son mayores y mis proclives a errores.

Y un aspect0 mis importante si cabe es que puede ser dificil integrar sistemas que puedan comprender
LDAP pero sean incapaces de utilizar Java. Finalmente, mostramos cdmo J N D I y LDAP pueden trabajar juntos, ofreciendo la soluci6n mas elegante:

1
I

LDAP

NIS

N DS

NT

Servicios de directorio y JNDI


Aqui utilizamos J N D I para comunicar con varios servidores LDAP. El creador de programas solo tiene que preocuparse por un protocolo en particular (LDAP) y un API (JNDI). Por supuesto, estamos confiando en que 10s distribuidores proporcionan interfaces a sus protocolos de propiedad. Sin embargo, esto no es un problema ya que, para estos servicios de directorio de gran aceptacion, hay productos adicionales que nos permiten comunicarnos con ellos via LDAP.

Las concesiones
Aunque J N D I proporciona un API comun para programacion a diferentes servicios de directorio, hay algunas concesiones que deben realizarse:
D Una concesion indica que hay mucho sobregasto. Por ejemplo, cada objeto DirContext (10s

objetos que utiliza J N D I para interactuar con un servicio de directorio) debe ajustarse a un numero de mktodos, muchos de 10s cuales nunca utilizari. Cuando implemente un objeto DirContext,es sencillo dejarlo vacio de mod0 que no cause problemas con su aplicacion, per0 si ariade peso extra en tkrminos de memoria y de tiempo de compilaci6n durante la ejecucion de programa. Veremos un ejemplo de esto mis adelante, en este mismo capitulo.

O Ademis, para que J N D I pueda mantener una interfaz comun, no siempre se ajusta a todas las funciones del servicio de directorio. U n buen ejemplo de 6ste es el comando LDAP compare.Nos permite comparar un valor particular de un atributo en una unica entrada en el servidor LDAP. El semidor LDAP debe devolver un c6digo resultado en lugar de una serie de resultados de busqueda completa, convirtiendo asi la operacidn de comparacion en un trimite ligero y ripido. Sin embargo, J N D I no se ajusta a una verdadera comparacion LDAP, porque LDAP es el unico semicio de directorio que apoya esta operaci6n. En su lugar, J N D I realiza una sencilla busqueda que recupera fisicamente la entrada en la memoria del servidor y realiza la opera4611 de comparacion en la aplicacion. El resultado es el mismo para la aplicacion per0 ya no contamos con 10s beneficios de la comparacion real LDAP.
0 Finalmente, n o es posible obtener acceso direct0 a la conexion del servidor de directorio, lo que

sipifica que es muy dificil implementar la reserva de conexion o comprobar la expiracion de una aplicaci6n. Para la mayoria de las aplicaciones, estos inconvenientes no suponen un serio problema. J N D I proporciona un API comun a una variedad de servicios de directorio, que esti incluido como parte estindar de Java, del mismo mod0 que JDBC proporciona un API estindar a las bases de datos relacionales. En algunos caso, J N D I puede ser el unico API disponible para un semicio de directorio en particular como es el caso de D N S o de un senidor de aplicacion Java como BEA WebLogic. Sin embargo, en algunos casos, las aplicaciones si necesitan acceso de bajo nivel a1 servicio de directorio y, si la aplicaci6n no necesita ninguno de 10s servicios que ofrece J N D I (corno almacenamiento y recuperation de objetos Java), puede que queramos optar por un API Java de bajo nivel. Por ejemplo, en LDAP esti el Netscape Directory SDK para Java, que es en realidad m6s elaborado que el API JNDILDAP. Es un SDKde c6digo abierto, dispon~ble en http://www.mozilla.org/directory/. J N D I puede que tampoco sea la mejor soluci6n cuando una aplicacion necesita manipular archivos en el sistema de archivos local. Si 10s objetos Java como 10s objetos Datasource para programacion JDBC no deben ser cargados, es mejor en este caso utilizar las clases estindar disponibles en el paquete j ava . io.

iPor que utilizar JNDI cuando tenemos LDAP?


Entonces, ipor qu6 necesitamos J N D I si podemos comunicar con 10s sistemas via LDAP? Asimismo, ipor quk necesitamos LDAP cuando tenemos J N D I ? Para responder a estas preguntas, estudiemos como podemos utilizar J N D I o LDAP de forma independiente.

LDAP sin JNDI


LDAP es un buen mod0 de convergir el acceso a datos de directorio mediante un unico protocolo. Resulta util n o solo en la programacion Java sino t a m b i h para otros tipos de aplicaciones. Por ejemplo, LDAP es un buen mod0 de proporcionar un libro de direcciones de red basado en un estindar (la mayoria de 10s paquetes de e-mail cuentan con la capacidad de consultar un servidor LDAP para busquedas de direcciones de e-mail) o simplemente de mantener un registro de 10s dispositivos de una red. J N D I ofrece la capacidad de comunicar directamente con diferentes servicios de directorio de red cuando no necesitamos LDAP. Por ejemplo, puede que necesite determinar si alguien ha accedido a una aplicacion determinada basada en su pertenencia a un grupo NIS concreto, o puede que necesite recuperar un registro MX en un servidor DNS. J N D I facilita la tarea a1 creador de programas en estos casos proporcionando un API consistente en vez de tener que aprender como hacer lo mismo utilizando diferentes grupos de API.

JNDI sin LDAP


Aunque podria proporcionar un servicio similar a LDAP para sus aplicaciones Java a traves de JNDI, esto so10 seria util para sus aplicaciones Java y probablemente tendria que repetirlo en cada aplicacion Java que grabe que necesite este tip0 de servicio. LDAP es un estindar abierto mantenido por Internet Engineering Task Force (IETF). Esto significa que es accesible desde diversos clientes y distribuidores. Esta es una de las extraordinarias caracteristicas de Internet y la raz6n por la que 10s protocolos basados en Internet han reemplazado a 10s protocolos de propiedad como medios primarios de comunicaciones en red. LY XML? Cuando XML fue lanzado por primera vez, hubo cierto debate sobre la posibilidad de que reemplazara a todas las tecnologias anteriores incluido Java y LDAP. Por supuesto, esto no ocurri6. En su lugar, XML se ha convertido en el estindar de facto para datos persistentes, en especial para situaciones en las que necesite intercambiar datos persistentes entre aplicaciones grabadas en diferentes lenguajes de aplicaciones (por ejemplo, entre Visual Basic y Java). XML t a m b i h tiene su funci6n en LDAP y en JNDI. Hay una especificaci6n XML concreta para LDAP llamada Directory Services Markup Language (DSML) que esti siendo desarrollada principalmente para distribuir informacidn de directorio a travks de un ~ r o t o c o l o de base XML-RCP como SOAP. Consiste en un Ienguaje de marcado para representar servicios de directorio en XML. Si quiere mis detalles, vaya a http://www.dsrnl.org/ .

DSML esti disefiado para reemplazar el mod0 estindar de intercambio de datos LDAP externos a1 protocolo LDAP. El estindar actual es el formato LDAP Data Interchange Format (LDIF) y ise es el que utilizaremos para mostrar nuestros ejemplos en este capitulo.

Ahora que ya tenemos un conocimiento bisico de 10s servicios de directorio, J N D I y LDAP, es el momento de ensuciarnos las manos trabajando. Para utilizar J N D I tal y como se describe en este capitulo necesitaremos lo siguiente:

O JDK 1.3 de Sun, que incluye J N D I estindar, o J N D I Software Development Kit (SDK) 1.2.2 (disponible en http://java.sun.com/jndi/). O U n servidor de directorio que cumpla las normas LDAP v3. El servidor Directorio de Netscape, disponible en http://www.iplanet.com/download/download/index.htrnl, se utilizaen este capitulo.

Sewicios de directorio y JNDI


Todos 10s ejemplos que encontrari en este capitulo utilizan 10s datos de prueba a r i u s .corn que viene en este servidor de directorio. Aunque J N D I esti incorporado en JDK 1.3 y superior, puede que todavia necesite obtener el archivo 1dap.jar de J N D I 1.2.2 para conseguir toda la funcionalidad, incluida la capacidad de utilizar 10s controles LDAP y de almacenar/recuperar objetos RMI en un servidor LDAP.

Instalacion de JNDI
~ s t o son s 10s pasos generales a seguir para empezar a funcionar en un sistema estindar:
0

Obtener informaci6n de su administrador de servidor LDAP o instalar un servidor que cumpla con 10s requisitos LDAP v3. Yo he utilizado varios servidores LDAP para diversos desarrollos, incluido openLDAP (http://www.openldap.org) en Red Hat Linux 6.2, el servidor LDAP gratis de Eudora para Windows (http://www.eudora.corn) y 10s servidores Iplanet 4 & 5 Directory (http:/1 www.iplanet.corn) tanto en Red Hat Linux 6.2 como en Windows 2000. Instalar JDK 1.3, que contiene J N D I y el proveedor LDAP bisico. Si no esti utilizando funciones avanzadas de LDAP como controles, no necesitari instalar nada mis except0 JDK 1.3. Si esti explorando funciones avanzadas LDAP, lea la pigina J N D I en http://java.sun.com/JNDI/ para mis informaci6n.

Ahora ya estamos preparados para utilizar J N D I y LDAP.

Proveedores de servicios JNDI


El usuario no puede utilizar J N D I sin utilizar un proveedor de servicios, por lo que primer0 debemos entender el concepto de proveedor de servicios. U n proveedor de servicios es u n grupo de clases Java que le permite comunicar con u n servicio de directorio de u n mod0 similar a1 que 10s dispositivos JDBC le permiten comunicar con una base de datos.
- -

Para que un proveedor de servicios estk disponible para su uso en J N D I debe implementar la interfaz Context. La mayoria de 10s proveedores de servicio que utilizari es probable que implementen la interfaz DirectoryContext, que extiende la interfaz Context para capacitar servicios de directorio. Esto significa que s610 tenemos que aprender a manejar J N D I para saber que las llamadas API conectan a un semicio de designaci6n o de directorio, mientras que el proveedor de servicios se preocupa de 10s detalles aburridos como el protocolo de red y 10s valores codificado/decodificado. Por desgracia, 10s proveedores de servicios no son la panacea para el uso de servicios de directorio. Debemos saber algo sobre el servicio de directorio subyacente de modo que podamos nombrar nuestras entradas correctamente y construir correctas consultas de busqueda. A diferencia de las bases de datos relacionales, 10s servicios de directorio no comparten un lenguaje de consulta comun como SQL. En J N D I 1.2,los proveedores de servicios pueden ajustarse a un concepto de federaci6n donde un proveedor de servicios puede pasar una operaci6n a otro proveedor de servicios si no entiende el designaci6n o el esquema de la operaci6n. Por ejemplo, si quisikramos encontrar el registro XM (este

Capitulo 2
contiene el sewidor de e-mail de destino preferido para un dominio) para un dominio concreto de DNS, per0 nuestro proveedor inicial de servicio era LDAP, no podria responder a la consults. Si hubiera federacibn, podria pasar la solicitud a1 siguiente proveedor de servicios de la lista de federaci6n y, si fuera un proveedor de servicios DNS, podria trarnitar la solicitud por nosotros. En una situaci6n ideal, esto deberia resultar transparente para el programador de la aplicaci6n. Sin embargo, corno esta es una caracteristica nueva, todavia n o ha sido probada ni implementada por cornpleto. En conc~usi6n, un proveedor de servicios permite a nuestras aplicaciones J N D I comunicar con un servicio de designaci6n/directorio. El resto de las interfaces, clases y excepciones giran todas alrededor de nuestra interacci6n con un proveedor de servicios.

Como obtener proveedores de servicios JNDI


Si descargarnos el SDK JNDI, veremos que, junto con el API y la documentaci6n, se incluye una serie de proveedores de servicios existentes. Estos incluyen proveedores para LDAP, NIS, C O S y el registro RMI y sistema de archivos. Muchos distribuidores diferentes tambikn facilitan proveedores de servicios para otros servicios de directorio, o corno sustitutos para 10s proveedores por defecto de Sun. Por ejemplo, Novel1 tiene un proveedor de servicios para NDS, mientras que tanto IBM corno Netscape cuentan con proveedores de servicios alternativos para LDAP. Resulta ficil cambiar entre proveedores de servicios. Por ejemplo, para utilizar el proveedor de servicios LDAP de Sun por defecto realizariamos una llamada corno ksta:
// Especlflcar qu6 c l a s e u t l l i z a r para rluestro e n v . p u t ( C o n t e x t . I N I T I A L CONTEXT FACTORY, "corn. s u n . j n d i . 1 d a p . L d a p C t x F a c t o r y " ) ;
proveedor JNDI

Ahora para utilizar el proveedor de servicios LDAP de IBM simplemente sustituiria com.sun.jndi.ldap.LdapCtxFactorypor el nombre completo del paquete del proveedor de servicios LDAP de IBM del siguiente modo:
/ / E s p e c i f i c a r qu6 c l a s e u t i l i z a r p a r a n u e s t r o e r ~ vp . u t ( C o n t e x t . I I I I T I A L CONTEXT FACTORY, "corn. ibrn. j n d i . L D A P C t x F a c t o r y t ' ) ;
proveedor
JIIDI

Puede encontrar una lista de proveedores de servicios actuales en http://java.sun.com/products/jndi/ serviceproviders. htrnl.

Como desarrollar su propio proveedor de servicios


Puede que tambikn necesite implernentar su propio proveedor de servicios si necesita utilizar un servicio de directorio (corno 10s dorninios de Windows N T o Bayan Vines) que todavia no tiene un proveedor de servicios. En el SDK JNDI, Sun facilita un ejemplo de c6mo grabar un proveedor de servicios. Esta tutoria J N D I esti disponible en http://java.sun.com/products/jndi/tutoriaI/index,htrnl. Sun tarnbikn proporciona un docurnento P D F que describe el proceso de grabar un proveedor de servicios en ftp://ftp.javasoft.com/ docs/jndi/jndispi.pdf. El proveedor de servicios LDAP de Netscape esti disponible corno proyecto de abierto en http://www.rnozilla.org~directory/.

Servicios de directorio y JNDl

Java y LDAP
Antes de que comencemos a examinar activamente el uso de LDAP en Java, debemos analizar brevemente el uso comun de LDAP en las aplicaciones de Java. En la actualidad, hay tres aplicaciones bisicas de LDAP en Java:

CI Control de acceso
0 0

Servicio de piginas blancas Directorio de procesamiento distribuido

Examinemos estas aplicaciones mis detenidamente.

Todas las aplicaciones dictan quC usuarios pueden acceder a ellas. Este acceso puede desde permitir el inicio a cualquier usuario que haga clic en el icono de la aplicaci6n hasta permitir el acceso unicamente a un usuario que se ajuste a un esciner de retina. La mayoria de las aplicaciones se encuentran entre estos dos extremos. El control de acceso puede descomponerse en autentificaci6n y autorizaci6n.

Autentificacion
La autentificacibn consiste en determinar q u i h es la persona que esti utilizando un elemento de software. Debido a la naturaleza de la informitica, nunca podemos estar cien por cien seguros de quikn es el usuario, per0 varios mecanismos de autentificaci6n aumentan las probabilidades de que el usuario sea quien dice ser. La autentificacion requiere el uso de un secret0 cornpartido, cuya forma mis comun es una contraseiia. El usuario facilita un nombre de usuario y una contraseha. El nombre de usuario se utiliza para buscar el registro de la persona en cuestidn en una base de datos (esta base de datos puede ser un simple archivo plano como el archivo p a s s w d U N I X o una sofisticada base de datos como LDAP) y si la contraseiia dada es la misma que la almacenada en la base de datos, entonces asumimos que el usuario es quien dice ser. La autentificaci6n basada en una contraseiia es la mis sencilla per0 uno de 10s mktodos menos seguros; puesto que las contraseiias son introducidas con el teclado, pueden ser detectadas en el trinsito por las redes o pueden ser ficilmente descifradas por alguien sin escrupulos que acceda sin autorizaci6n a la base de datos de contraseiias. En el actual mundo de Internet, la mayor amenaza para las contraseiias (mis all5 de preguntar a1 usuario personalmente por su contraseiia) es viajar por la red libremente. Por lo tanto, es mejor tomar medidas para proteger las contraseiias a la hora de viajar por la red. Dos mecanismos muy comunes son M D 5 y Secure Socket Layers (SSL). En MD5 el cliente crea en primer lugar una refundici6n MD5 de la contraseiia antes de introducirla en la red. El servidor compara entonces esta refundici6n con la que ha almacenado en su base de datos. Aunque este metodo evita que alguien adivine la contraseiia de texto y que se registre en otros sistemas, no evita que alguien robe la contraseiia refundida. Esta contraseiia refundida robada puede ser utilizada igual que una contraseiia de texto robada para acceder a1 sistema (conocido como ataque "man in the middle", algo asi como "hombre en el medio"). O t r o inconveniente es que la mayoria de 10s sistemas no almacenan sus contraseiias como M D 5 (aunque ciertas implementaciones BSD s i l o hacen) porque se puede ver forzado a cambiar las contrasefias de todos antes de poder implementar este sistema. C o n SSL toda la conexi6n de red esti cifrada. Esto no s61o protege la contraseiia sino que tambikn protege cualquier dato transferido entre el cliente y el servidor. Esta es la raz6n por la que SSL se utiliza

Capitulo 2
con frecuencia para proteger aplicaciones de e-comercio. TambiCn resulta util en LDAP porque 10s servidores LDAP a menudo contienen datos sensibles como numeros de identification personal, numeros de licencia de dispositivos, etc. N o queremos que estos datos viajen de forma insegura por la red igual que no queremos que lo hagan las contraseiias. SSL tambien aiiade otra forma de autentificacion en conjunto: el certificado digital. Los certificados digitales utilizan el cifrado publico de claves para reforzar el proceso de autentificacion. Bajo el cifrado pGblico de claves, el usuario cuenta con una clave privada a la que solo 6 1 tiene acceso. Todos 10s datos cifrados por la clave privada solo pueden ser descifrados por la clave publica y viceversa. El servidor tiene acceso a su clave publica. Con SSL (que cifra toda la transferencia de datos), el servidor envia al usuario algunos datos para cifrar con su clave privada. El usuario cifra 10s datos y 10s devuelve a1 servidor. Si el servidor puede descifrar 10s datos con la clave publics y 10s datos coinciden, entonces se asume que se trata del usuario. El estindar de certificado digital (X.509) es una extension del estindar de servicios de directorio original. De este modo, LDAP es uno de 10s modos mis eficientes de gesti6n de certificados digitales. Sin embargo, hay que sefialar que esta autentificacion de usuario ocurre en realidad despub de que el servidor SSL haya sido autentificado. LDAP tiene la capacidad de ajustarse a un amplio espectro de servicios de autentificaci6n incluido contraseiias, certificados digitales y el protocolo Simple Authentication and Security Layer (SASL).

Autorizacion
Despuks de haber autentificado a alguien, necesitamos determinar quk les esti permitido hacer. Por ejemplo, podriamos decidir que solo 10s miembros de 10s Enanitos tienen derecho a acceder a 10s archivos de BlancaNieves. Tambikn podriamos aiiadir granularidad rnis fina indicando simplemente si alguien tiene acceso o no. Por ejemplo, podriamos establecer que 10s miembros del conse j o Jedi tienen plenos derechos sobre elementos de la base de datos Fuerza, mientras que 10s miembros de 10s Caballeros Jedi tienen capacidad para editar ciertos elementos en la base de datos Fuer za,mientras que padawan solo tiene capacidad de leer la base de datos Fuerza. Podemos utilizar LDAP para desarrollar sofisticadas politicas de autorizaci6n.

Servicios de paginas blancas


Los servicios de piginas blancas permiten a alguien buscar usuarios basindose en atributos contenidos en sus entradas. Por ejemplo, puede buscar la direccidn de e-mail de Mark Wilcox y obtener el numero de telkfono de la oficina de Ingenieria, el numero de edificio de Recursos Humanos, etc. Se llaman piginas blancas porque este tip0 de informaci6n es similar a1 tip0 de informaci6n que puede encontrar en las piginas blancas de telkfonos. Este tip0 de servicios son 10s rnis publicos de todas las operaciones LDAP y son para lo que muchos usuarios, si no todos, utilizan LDAP. En Java, lo estamos situando en segundo lugar porque la mayoria de 10s servicios de piginas blancas se facilitan mediante un cliente LDAP que se encuentra en un paquete de email como Netscape Messenger o Microsoft Outlook en vez de a travCs de una aplicaci6n Java. Las aplicaciones Java realizan normalmente esta funcion bien como segundo plano de una interfaz LDAP de pigina Web o para proporcionar servicios de flujo de trabajo en una aplicacion Java de empresa. Como ejemplo, estudiemos una sencilla situacidn en la que Juan introduce una solicitud de orden de compra (PO) electronics de 100 artilugios de la marca Acme. La aplicaci6n de compra tiene una regla comercial que establece que despuks de que alguien introduzca una solicitud (PO) debe ser enviada a1 encargado de autorizaciones de P O de su grupo. Por lo tanto, la aplicacion consulta LDAP para saber quikn es el autorizador de P O para el grupo de Juan en LDAP y les envia una notification de e-mail utilizando el atributo de e-mail LDAP del autorizador.

Servicios de directorio y JNDI

Directorio de procesamiento distribuido


Uno de 10s segmentos de crecimiento mis ripido de programacidn de servidor es la programacidn de red distribuida, donde una aplicacidn utiliza cddigo que realmente reside independientemente de la aplicacion ejecutada. El c6digo puede estar en una JVM independiente (o miquina similar tipo servidor CORBA) o en una miquina fisica diferente situada a1 otro extremo del mundo. A menudo utilizamos este tip0 de programacidn para facilitar la reutihaci6n del cddigo de legado existente o para mejorar el rendimiento descargando un gran volumen de procesamiento en una miquina distinta. En Java, hay tres arquitecturas distribuidas diferentes disponibles:

O Remote Meted Invocation (RMI) O Common Object Request Broker Architecture (CORBA) O Enterprise JavaBeans (EJB)
Las tres arquitecturas proporcionan un servicio de registro que una aplicacidn de cliente utiliza para localizar el codigo distribuido. Debido a que su especificacidn fue desarrollada despuks de JNDI, EJB utiliza J N D I para sus servicios de registro. RMI y CORBA utilizan sus propios servicios independientes de registro. Uno de 10s problemas de estos servicios es que no proporcionan un mecanismo que permite buscar en su registro para saber quk objetos estin disponibles para su uso. Con J N D I y LDAP el usuario puede proporcionar a estos servicios referencias indirectas con el objeto Reference JNDI. Por ejemplo, puede tener una entrada con un nombre de "Real Time S t o c k Q u o t e s e r v i c e " que tiene un atributo que contiene la localizacidn de red real para el objeto RMI o CORBA. Este tip0 de servicio facilita la comprensidn de su c6digo y le otorga mis flexibilidad en su aplicaci6n. Por ejemplo, si necesita desplazar un determinado objeto distribuido a un nuevo servidor, en lugar de tener que cambiar todas las aplicaciones que referencian ese objeto, s61o tiene que cambiar su posici6n en LDAP y todas las aplicaciones de cliente actualizarin sus posiciones automiticamente la pr6xima vez que referencien el objeto. LDAP tambikn puede almacenar otros atributos descriptivos en una entrada, de modo que el usuario podria almacenar mejores descripciones de su objeto en el directorio para construir piginas blancas para objetos. Quienes han estado implicados en proyectos de sus compaiiias para el desarrollo de libreria de codigos centralizadas encuentran a menudo que el desarrollo del cddigo era la parte ficil; conseguir que el c6digo sea ficil de encontrar en la parte dificil. Utilizar LDAP como un directorio de clase es una soluci6n a estos problemas. Podriamos afiadir otros elementos a la descripci6n de nuestro ejemplo de objeto almacenado. Por ejemplo, podriamos aiiadir elementos como el lenguaje de desarrollo utilizado, una anotacidn sobre su propdsito y el nombre del creador del programa o del equipo de desarrollo.

Configuration de la aplicacion
LDAP tambikn puede utilizarse para almacenar informaci6n de configuracidn sobre una aplicacibn. Esto es especialmente Gtil cuando la aplicaci6n la utiliza el mismo usuario per0 en diferentes miquinas y seria util proporcionar la misma informaci6n de configuraci6n sin tener en cuenta la miquina utilizada por el usuario para acceder a ksta. A continuacidn dejaremos de hablar en tkrminos hipotCticos y de explicar 10s conceptos bisicos para introducirnos en la prictica. En el resto de este capitulo, veremos algo de c6digo real y cdmo realizar operaciones LDAP bisicas con JNDI.

Capitulo 2

Operaciones LDAP
Antes de que podamos realizar cualquier tipo de operaci6n en un senidor LDAP, debemos en primer lugar obtener una referencia y una conexi6n de red para el servidor LDAP. Tambikn debemos especificar c6mo queremos estar seguros con respecto a1 servidor, bien de forma anonima o como un usuario autentificado. Muchos servidores LDAP accesibles a Internet permiten a l g h tip0 de acceso an6nimo (generalmente funciones de s61o lectura para atributos como direcciones de e-mail y n6meros de telkfono), per0 LDAP tambikn se ajusta a caracteristicas de seguridad muy avanzadas a travks de ACL que dependen de quien autentifica la conexi6n. Por ejemplo, un servidor LDAP puede tener diversos niveles de derechos para cualquier entrada determinada: Usuarios an6nimos pueden acceder a la direcci6n de e-mail y al nfimero de tekfono de una empleado.

o El empleado puede ver la entrada completa de dichos usuarios per0 s6lo puede modificar ciertos
atributos como el nfimero de telkfono, la contrasefia y el nfimero de despacho de la oficina.
0

El gestor de un usuario puede actualizar el nfimero de telkfono de un empleado y el nhnero de despacho de la oficina per0 ningun elemento mas. Tambikn puede acceder a1 registro cornpleto del empleado. U n grupo reducido, 10s Administradores d'el Directorio, tiene plenos derechos sobre el servidor completo incluida la posibilidad de afiadir y eLminar cualquier entrada.

Operaciones LDAP estandar


Existen algunas operaciones estindar en LDAP. Son las siguientes:
O O O

Conexi6n a1 servidor LDAP Asociaci6n a un servidor LDAP (puede considerar este paso como autentificaci6n) Realizaci6n de una serie de operaciones LDAP:
0 Bfisqueda del servidor 0 Adici6n de una nueva entrada 0
O

Modificaci6n de una entrada Eliminaci6n de una entrada

Desconexion de un servidor LDAP

Analizaremos cada una de las operaciones anteriores, realizando demostraciones con ejemplos siempre que sea pertinente.

Conexion al servidor LDAP con JNDl


Primero debemos obtener una referencia para un objeto que implemente la interfaz Dircontext. En la mayoria de las aplicaciones, utilizaremos el objeto InitialDirContext que tome una tablade

Capitulo 2
Para asociar especificarnente a1 semidor, debernos facilitar el rnedio con el rnCtodo para nuestra autentificacih (por ejernplo, "simpleM, SSL, o SASL). DespuCs debernos especificar el D N de la entrada que desearnos asociar y la contrasefia de la entrada:
Hashtable env
=

r~ewHashtable ( ) ; cor~exitr~

//

Asi envia en i d y l a e n v . p u t ( C o n t e x t . PROVIDER e n v . p u t ( C o n t e x t . SECURITY e n v . p u t ( C o n t e x t.SECURITY

c o n t r a s e f ~ acomo t e x t o e n l a URL, "myhost") ; AUTHENTICATION, " s i m p l e " ) ; P R I N C I P A L , MGR D N ) ; env.put(Context.SECUR1TY C R E D E N T I A L S , MGR P W ) ;

//

Obtener DirContext

una

ctx

referencia a un contexto d e dlrectorio n e w I n i t i a l D i r C o n t e x t (env) ;

Seguridad simple, SSVTLS y SASL


La Gltirna especificacidn LDAP, LDAP v3, perrnite tres tipos de seguridad:

SASL

Estudiernos cada tip0 sucesivarnente.


Simple

Seguridad simple significa que el usuario s61o necesitari au~entificar a1 servidor utilizando I D y contrasefias de texto estindar sin ningGn cifrado en la red. Este es con diferencia el rnis cornGn y el rnenos seguro de 10s distintos rnCtodos de autentificacih. Es inseguro por dos rnotivos: el prirnero consiste en que 10s I D y contraseiias de 10s usuarios son transrnitidas a1 semidor a travCs de una red pGblica, donde cualquiera puede robar 10s I D y las contrasefias de la red; en segundo lugar, nada garantiza que la persona que introduce el I D y la contrasefia de usuario es el verdadero titular de ese I D y de esa contrasefia.

El protocolo Secure Socket Layer fue desarrollado por Netscape Communications para mejorar la seguridad de las transacciones de base Web. Se ha convertido en una norrna oficial llarnada Transport Layer Security (TLS), per0 todavia se denornina a rnenudo SSL. SSL le perrnite cifrar su transacci6n cornpleta en la red, dificultando a cualquiera la tarea de robar la inforrnaci6n (corno su I D o sus contraseiias). SLL estindar n o verifica la identidad de la persona que introduce el I D y la contrasefia de usuario per0 si certifica que la rniquina desde la que el usuario esti introduciendo el I D y la contrasefia es "el verdadero servidor". La rnayoria de 10s servidores que implementan SSL tarnbikn se ajustan a 10s certificados cliente (10s certificados son archivos de texto que son utilizados para confirmar la identidad del servidor y del cliente) para la autentificacibn del usuario. En vez de presentar un I D y una contrasefia de usuario al sisterna, puede presentar un certificado a1 servidor. Si el certificado que presenta coincide con un certificado perrnitido, el acceso esti garantizado.

Los certificados se consideran mks seguros porque son dificiles de falsificar. Sin ernbargo, 10s certificados se almacenan normalmente como un archivo en una mkquina de usuario local, lo que significa que la mdquina cliente estk comprometida, entonces puede utilizarse un certificado del mismo modo que puede utilizarse un ID y una contraseiia robada. Cuando 10s certificados son

Servicios de directorio v JNDl


almacenados localmente, debe desarrollarse u n mecanismo para recuperarlos si la mdquina en la que esta'n almacenados falla. Los certifi;cados pueden ser almacenados en tarletas inteligentes en lugar de archivos en una mciquina local para mayor seguridad y fiabilidad. La emisidn y gestidn de cert$icados de cliente se encuentra todavia en fuses tempranas de desarrollo.
SASL Simple Authentication and Security Layer (SASL) es un estindar de Internet para implementar mecanismos de autentificacion ademis de 10s mktodos Simple o SSL. Existen dos mecanismos SASL conocidos. U n o es el MD5 que ya hemos visto con anterioridad, basado en la comparacibn de contrasefias refundidas. M D 5 no cifra la transaccion y no resuelve el problems de "quikn introduce la contrasefia". Si la contraseiia MD5 refundida es robada en su camino hacia el servidor, un hacker podria utilizarla para acceder al sistema, del mismo mod0 que si se tratara de texto. Sin embargo, si hace que resulte mis dificil adivinar la contrasefia original por lo que, si un hacker roba la contrasefia refundida, no podri adivinar la contrasefia original para intentar utilizarla para acceder a otros sistemas. El segundo mecanismo SASL de uso extendido se denomina Kerberos. Kerberos cifra la transaccion y, en una red con conocimiento de Kerberos, es muy ficil implementar un entorno de unico registro debido a1 mod0 de funcionamiento de Kerberos. Sin embargo, gestionar una red Kerberos supone rnucho tiempo y muchos recursos, por lo que muchas organizaciones no han implementado Kerberos todavia. Puede grabar ficilmente sus propios mecanismos SASL, si su sewidor LDAP se ajusta a ellos. Asi, seria posible capacitar la autentificacion biomktrica, una vez e s t i disponible (o si su organizacibn ya tiene acceso a la tecnologia). La autentificacion biomktrica hace uso de parte del cuerpo del usuario, como su huella dactilar o su iris, para el I D y la contrasefia de usuario. Estos sistemas son muy seguros.

Autentificacion en LDAP v2 y LDAP v3


En LDAP v2, todos 10s clientes tenian que autentificarse a si mismos antes de ejecutar cualquier operacion. En LDAP v3, sin embargo, si un cliente no se autentificaba a si mismo antes de ejecutar una operacion, se asumia que la conexion era autentificada anonimamente.

Busqueda en un servidor LDAP


La operacion rnis comun en cualquier servidor LDAP es la operacion de bfisqueda. Cualquier aplicacion LDAP avanzada utiliza la b ~ s q u e d a como funcionalidad central. En esencia, todas las funciones de busqueda toman un controlador de conexion LDAP, la base desde la que iniciar la busqueda, el espectro de la busqueda y el filtro de la busqueda. U n filtro de bhqueda es como una consulta SQL en la que indica a1 sewidor 10s criterios a utilizar para encontrar entradas que cumplan 10s criterios. Las busquedas siempre utilizan un nombre de atributo y un valor que buscar. Los filtros utilizan 16gica y comodines booleanos. Algunos servidores, como el servidor de Directorio Netscape, se ajustan a capacidades de consulta incluso mis avanzadas, del tip0 "suena como", por ejemplo.

Para 10s ejemplos de busqueda de esta seccidn, accederemos a 10s datos de muestra arius.com que esta'n incorporados a Netscape Directory Server.

Capitulo 2

Filtros LDAP de ejemplo


Algunos filtros LDAP tipicos aparecen en la siguiente tabla: Descripcih Filtro LDAP sn = Carter s n = Ca*

I Buscar todos lor usuarios con apellido Carter


Buscar todos 10s usuarios con apellido que empiece por "Ca" Buscar todas las clases de objeto del tip0 GroupofUniqueNames que tengan "Managers" en su Nombre Comhn

( c n = * Managers * ) (objectclass=groupof~niquenames))
(h

En JNDI, utilizamos el mitodo de bhqueda de la interfaz D i r C o n t e x t . Esto devolveri un objeto N a m i n g E n u m e r a t i o n si la bhqueda es realizada con 6xito. Mis adelante, en esta secci6r1, mostraremos 10s distintos modos de manipular 10s valores de este objeto para obtener atributos y valores de cada entrada recibida.

Determinar el alcance de LDAP


Cuando realiza una bhqueda, debe especificar el nodo (a1 que nosotros hacemos referencia como la base) del irbol que desea iniciar, asi como el alcance la busqueda. El alcance define exactamente qu6 proporci6n del irbol desea buscar. Hay tres niveles de alcance. Alcance LDAP-SCOPE-SUBTREE
LDAP-SCOPE-ONELEVEL

Descripcih Este alcance comienza en la entrada base y busca todo lo que se encuentra por debajo, incluida la entrada base. Este alcance busca el irbol completo empezando un nivel por debajo de la entrada base. N o incluye la entrada base. Este alcance buscahicamente laentrada base, Gtil si deseaobtener s61o 10s atributos/valores de una entrada.

LDAP-SCOPE-BASE

A continuaci6n examinaremos estos tres niveles de alcance con la ayuda de algunos diagramas.

LDAP-SCOPE-SUBTREE
La primera figura, a continuaci6n, ilustra una bhqueda utilizando LDAP-SCOPE-SUBTREE:

Servicios de directorio v JNDl

Search Base= dc=a~r~us, dc=com root

Aqui ofrecemos un ejemplo de busqueda u t i l i z a n d o ~ ~ ~ P - S C O P E - O N E L E V E L :

Search Base; dc=a~r~u dc=corn s

'

root

Finalmente, presentamos una b h q u e d a U ~ ~ ~ ~ ~ ~ ~ ~ O L D A P - S C O P E - B A S E :

Capitulo 2

Search Base= dc=airlus, &=corn -. -

root

Ejecucion de una busqueda JNDI


Jealizamos una busqueda utilizando el metodo s e a r c h ( ) de un objeto que implementa la interfaz DirContext (como laclase I n i t i a l D i r ~ o n t e x t ) El . requisito minimo para esto es la base de busqueda y el filtro, aunque hay otros parimetros que podemos utilizar para ayudar a gestionar 10s resultados. Deberiamos destacar que en la mayoria de 10s API de LDAP debemos especificar el alcance como un parimetro en el metodo de blisqueda LDAP. En JNDI, sin embargo, el alcance seconfipra en el objeto S e a r c h C o n t r o l s , que es un parimetro opcional a1 de la funcibn s e a r c h ( ) de la interfaz DirContext (la clase I n i t i a l D i r C o n t e x t proporciona una implementacibn de la funcibn s e a r c h ( ) ). Por defecto, esti establecido en subtree. La blisqueda es en realidad ejecutada con cualquier objeto que tenga que implemente I a i n t e r f a z D i r C o n t e x t , como l a c l a s e I n i t i a l D i r C o n t e x t . Para nuestro primer ejemplo,mostraremos un ejemplo de busqueda muy sencillo, en el que el filtro de busqueda es " s n = C a r t e r " . Este devolveri todas las entradas que tengan un apellido (el atributo especificado por el mnem6nico "sn") Carter. El primer ejemplo es una busqueda anbnima. Los ejemplos no estin basados en G U I para facilitar la comprensibn de lo que esti ocurriendo, per0 no hay ningun motivo por el que no puedan ser incluidos en una GUI. Recuerde que todos 10s cbdigos fuente para 10s El . c6digo queda como ejemplos descritos en este capitulo pueden ser descargados en h t t p : / ~ . w r o x . c o m sigue:
/ / B6squeda an6nima est6ndar import java. util .Hashtable; import java.util.Enumeration;

import j avax. naming. +; import j avax.naminq.directnry. * ; public class JNDISearch


{

/ / Implementacihn de cor~texto inicial public static String INITCTX = "corn.sun. jndi. 1dap.LdapCtxFactory"; public static String MY HOST = "ldap://localhost:389"; public static String MY SEARCHBASE = "o=Airius.com"; public static String M Y FILTER = " (sn=Carter)"; public static vcid mainiString args [ I ) [

/ / Hashtable para informaci6n del medio Hashtable env = new Hashtable(); / / Especificar qu6 clase utilizar para nuestro proveedor JNDI env.put(Context.INITIAL CONTEXT FACTORY, INITCTX);
/ / Especificar host y puerto a utilizar para servicio d e directorio env. put (Context.PROVIDER URL, MY HOST) ;

/ / Obtener una referencia para un context0 d e directorio DirContext ctx = n e w InitialDirContext (env);
/ / Especificar el alcance d e la bhsqueda SearchControls constraints = n e w SearchControls ( ) ; cor~straints.setSearchScope(SearchContro1s.SUBTREE SCOPE);

/ / Realizar la b6squeda real. Le otorgamos un base de bfisqueda, un filtro / / y las restricciones contenidas en el alcance d e la bfisqueda NamingEnumeration results = ctx.search(MY SEARCHBASE, MY FILTER, constraints) ; / / Ahora exarninamos 10s resultados d e la bfisqueda while (results ! = null & & results.hasMore()) [ SearchResult sr = (SearchResult) r e s u l t s . n e x t 0 ;
String dn = sr.getName0; System.out .println("Distinguished Name is " + d n ) ; Attributes attrs for
=

sr.getAttributes();
;)

(NamingEnumeration ne = attrs.getAll( ) ; ne. hasMoreElerner~ts ( ) Attribute attr = (Attribute) ne.next ( ) ; String attrID = attr.getID( ) ;

System.out.println (attrID + " : " I ; for (Enumeration vals = attr.getAll();vals.hasMoreElemer~ts();){ System.out .println ("\t" + vals.nextElement ( ) ) ;

catch (Exception e ) { e.printStackTrace0; System.exit ( 1 ) ;

I I I
Despuks de compilar y ejecutar este c6dig0, el resultado debe aparecer de mod0 similar a 10s resultados que aparecen en la siguiente captura de pantalla:

Capitulo 2

Como funciona el programa de busqueda


Realizamos una bdsqueda utilizando el m e t o d o s e a r c h ( ) de un objeto que implements la interfaz D i r C o n t e x t (con10 la clase ~ n i t i a l ~ i r c o n t e x tEl ) .requisite minimo para esta blisqueda es la base de bhsqueda y un filtro. Existen otros parimetros que podemos utilizar para ayudar a gestionar 10s resultados. Si la bdsqueda se realiza con &xito,se obtendri un objeto ~ a m i n g ~ n u m e ri a ot n. Despuks de obtener el context0 inicial (a1 que fijamos la variable c t x ) , especificamos el alcance de la blisqueda. Si no especificamos un alcance, JNDI asumir6 un alcance s u b t r e e , por lo que esta linea siguiente es en realidad redundante per0 resulta litil para mostrar c6mo especificar el alcance. Analicemos ahora el proceso de funcionamiento de este c6digo. En primer lugar, establecemos en alcance desubtree:

DespuCs de especificar el alcance, podemos realizar la verdadera bdsqueda del siguiente modo:
/ / Ej e c u t a r l a v e r d a d e r a b d s q u e d a N s m i n g E n u m ~ r a t i i ~r re ~. s u l t s = ctx.searchIMY-SEARrHBASE, cMonstraints;; MY-FILTER,

La clase N a m i n g E n u m e r a t i o n es equivalente a la clase SearchResults de SDK Netscape Directory para Java. Cada elemento del o b j e t o ~ a m i n g ~ n u m e r a t i o contendri n un o b j e t o ~ e a r c h ~ e s u que l t podemos recuperar:
SearchResul t sr
=

[ S e a r c h R e s u l t ) results . n e x t

( ) ;

Servicios de directorio y JNDl


Despuis podemos obtener el D N de una entrada:
String
dr,
=

sr.getName ( 1 ;

Para obtener 10s atributos de una entrada utilice el metodo g e t A t t r i b u t e s () de la clase SearchResults:
Attributes attrs
=

sr.gttAttributes 1 ) ;

Este metodo devolveri un objeto concreto que implements la i n t e r f a z ~ t t r i b u t e s (la clase ev ~ n i t i a l ~ i r ~ o n td e xute l v e u n o b j e t o ~ a s i c A t t r i b u t e s ) . Despues de conseguir un o b j e t o ~ t t r i b u t e (recuerde s que es una clase de colecci6n), podemos entonces repasar 10s atributos utilizando un objeto N a m i n g E n u m e r a t i o n como iste:
L L i N a r n i n q E n u m t r a t i o r 1 tie
= a t t r s . q e t A l 1 ( ) ; r~e.hasMoreElerner,ts ( 1 ;) . A t t r i b u t e a t t r = I A t t r i t j ~ ~ t e ) r ~ e . nf e ) ;x t Strin3 attrID = attr.qetID();

System.t~ut.println[attrID +
frlr ( E r , l u m e ~ - a t i o nv a l s
=

":");

a t t r . g e t A l 1 ( i ;vsls. h a s M o r e E l e r n e r ~ t s1 ) ; 1 S.i"tem.~:8~~t.prir~t1r~("\t" + v a l s . r l e u t E l e m e r ~ (t ) ) ;

La clase N a m i n g E n u m e r a t i o n nos ofrece mktodos que podemos utilizar para examinar cada atributo obtenido en nuestra bhsqueda. Cadaelemento del o b j e t o ~ a m i n g ~ n u m e r a t i o contendri n un objeto A t t r i b u t e que representa un atributo y sus valores. Cada elemento del o b j e t o ~ t t r i b u t es e un objeto que ha implementado la i n t e r f a z ~ t t r i b u t e (la clase I n i t i a l D i r C o n t e x t u t i l i z a o b j e t o s B a s i c A t t r i b u t e ) . E l m i t o d o g e t I D ( ) delainterfaz ~ t rib t u t e devuelve el nombre del atributo. El mitodo g e t ~ l( )l de la i n t e r f a z ~ trt i b u t e devolveri un objeto E n u m e r a t i o n Java estindar, al que podemos acceder para obtener 10s valores del atributo individual. En todos 10s servidores LDAP hay ciertos atributos que no estarin disponibles para usuarios an6nimos debido a 10s controles de acceso sobre el servidor. Tambiin hay ciertos atributos que puede que s61o estkn disponibles para ciertos usuarios privilegiados (la escala salarial, por ejemplo, puede que sblo sea visible para el departamento de Recursos Humanos).

Busqueda autentificada
El siguiente apartado muestra cbmo podemos modificar el ejemplo para una blisqueda autentificada:
import import import import public

ja v a . u t i l . H a s h t a b l e ; j a v a .u t i l .E n u m e r a t i u n ; ja v a s . n a m i n g . *;
j a v a s . r ~ a r n i n g . d i r e c t o r y .+ ; c l a s s JNDISearchAuth { s s s s s tatic String t a t i c S t rirlg tatic String tatic String t a t i c S t rirlg INITCTX "com.sun.jr~di.ldap.LdapCtxFact~~ry"; MY HOST = " l d a p : / / l o c a l h o k ; t : 3 8 9 " ; MGR D N = " u i d = k v a u g h a n , o u - P e o p l e , o=airius.cornn; MGR-PW = " b r i b e r y " ; MY-SEARCHBASE = " o = A i r i u s . corn";
=

public public public public public public

static

S t r i n g MY-FILTER

" ( s n = C a r t e r ) ";

Capitulo 2

public static void main(String args[] 1 [ try I / / Hashtable para informacihn del rnedio Hasiltable env = new Hashtable ( ) ;
/ / Especlflcar la clase a utlllzar para nuestro proveedor JNDI env.put[Car~text.INITIAL~CONTEXT~FAI_'TORY, INITCTX); / / Infarmacihn de sequridad / / Nos autentifica a1 servidar env .put (Context.PROVIDER [JRL, MY HOST) ; env.put(Context.SECUR1TY AUTHENTICATION, "simple"); env.put (Context.SECURITY PRINCIPAL, MGR D N ); env.put(Context.SECURITY~CREDENTIALS, MGR-PW);
//

Resto de la clase sir, alterar ; ClirContext ctx = new IrlitialDirCorltext( e n v )

SearchCor~t rols constraints = new SearchControls ( ) ; constrairlts.setSearchScope ( SearchControls. SUBTREE SCOPE) ;


-

NamingEnumeratlor, results

ctx.search(MY-SEARCHBASE, MY-FILTER, c o n s t r a l n t ~; )

/ / At,ora repasar 10s resultados de la brisqueda while (results ! = null & & results.hasMore()) { SearchResult sr = (SearchResult) results.next(j;

String d n = s r . g e t N a m e 0 ; System.out .prir~tlr~("Distinguished Name Attributes attrs


=

is "

d n );

sr.getAttributes();
) ;)

for (NamingErlumeration ne = attrs.getAll( ) ; ne.hasMoreElements ( Attribute attr = (Attribute) ne.rtext ( ) ; String attrID = attr.getID();

System.out.println(attr1D t " : " I ; far (Enumeration vals = attr.getAl1 ( ) ; vals. hasMoreElen~ents ( ) ;) { System.out .println ("\t" t vals .nextElerner,t I) I ;

1
I

catch (Exception e ) { e.printStackTrace ( ) ; System.exit ( 1 ) ;

Este segundo ejemplo de blisqueda es el mismo que el primero, except0 en que nos hemos autentificado a1 servidor. Por ello, si intenta compilar y ejecutar este ejemplo, veri que produce exactamente el mismo resultado que antes. Observe que por defect0 el servidor LDAP devuelve todos 10s atributos de la bGsqueda. Sin embargo, puede que haya ocasiones en las que no deseemos estos resultados porque s610 nos interesen ciertos atributos.

Servicios de directorio v JNDI

Restringir 10s atributos presentados


En nuestro tercer ejemplo, solicitamos que s61o se muestren 10s atributos nombre comdn (cn) y direcci6n de e-mail ( m a i 1) :
import import ivpqrt import public java.util.Hashtab1e; j ava. u t i l . Enumeration; j a v a x . naming. *; j a v a x . n a m i n g . d i r e c t c > r y. j ; c l a s s JNDISearzhAttrs {

/ / 1mplerrter~taci;~r d~e z ~ ) n t e x t o i n i c i a l p u b l i c s t a t i c S t r i n g INITCTX = "corn. s u n . j r d i . l d a p . L d a p C t x F a c t o r y Y ' ;


public public public statlc static static String String MY-HOST = " l d a p : / / l o c a l h o s t : 3 8 9 " ; MY-SEARCHBASE = " o = A i r i u s . corn";
=

S t r i n g MY-FILTER

" ( s n = C a r t e r )";

/ / E s p e c i f i c a r quk a t r i b u t ~ se s t 6 b u s c a n d o p u b l i c s t a t i c S t r i n g MYpATTKSII = [ " c n " , " r n a i l " ] ; public s t a t i c void rnain(String a r g s [ ] ) [ try i / / H a s h t a b l e p a r a i n f o r m a c i 6 n d e l rnedio H a s h t a b l e e n v = new H a s h t a b l e ( ) ; / / E s p e c i f i c a r qu6 c l a s e u t i l i r a r para nuestro proveedor e n V . p u t ( C o n t e x t . INITIALpCONTENTpFACTORRi, I N I T C T S ) ; e n v . p u t ( C o n t e x t . PROVIDERpURL, MY-HOST) ; / / O b t e n e r u n a r e f e r e n c i a a un c o r j t e x t o d e d i r t c t o r i o D i r C o n t e x t c t x = new I n i t i a l D i r C o n t e x t ( e n v ) ; SearchControls constraints
=

JNDI

new

SearchControls ( ) ;

cor~strair~ts.setSearct~Scope(SearchCor~trols.SUBTREE-SCOPE);
Namir~gEnurneratim r e s u l t s = c t x . s e a r c h ( M Y SEAKCHBASE,MY FILTER, c o n s t r a i n t s ) ; w h i l e ( 1 - e s u i t s ! = r ~ u l l & & r e s u l t s . hasMcre ( ) ) { SearchResult s r = (SearchResult) r e s u l t s . n e x t ( ) ; S~L-ing ijrl = s r . g e t N a m e ( ) + ", " + MY-SEARCHBASE; S y s t e r r 1 . 5 u t. p r i r ~ t l r ( j " D i s t i n g u i s h e d Name Attributes i f (ar
==

is

" + dn);

ar

ctx.getAttributes (dn,

M Y ATTKS);

Systern.out.println("Entry " + d n " h a s none a f


{

null )

{ t

the

specified

attributes\nM);

1 else
for

( i n t i =O;i<MY A T T R S . l e n g t h ; i t t ) 1 A t t r i b u t e a t t r = ar.get(MY ATTRS[il); i f ( a t t r != n u l l ) [ Systern.out.println(MY ATTRS[i] + " : " ) ; f o r (Enumeration v a l s = a t t r . g t t A l 1 ( ) ;vals.t~asMoreElemer~( ts ); ) { S y s t e r n . o u t . p r i n t l n ("\t" + v a l s . n e x t E l e r r ~ e n t( ) ) ;

Capitulo 2

Como acabamos de especificar 10s atributos nombre com6n y mail, esta vez el resultado restringido sera el siguiente:

L i diferencia entre este cddigo y nuestros ejemplos de bdsqueda anteriores es que ahora limitnmos el ndmero de atributos que deseamos recuperar.
Hemos creado una matriz s t r i n g que enumeraba los atributos que deseabnmos:
r ' 1 1 P 1 i c s t a t i c S t r i r i q MY-A'l'TRS[I
=

("cr~","mail");

Para recuperar este conjunto de atributos utilizamos en metodo g e t A t t r i b u t e s ( ) de la interfnz D i r C o n t e x t , donde facilitamos el DN de una entrada especifica y la matriz de atributos.
Attributes
a r
=

ctw.q~tAttributes (dn,

MY-ATTRS);

Esto devolveri un objeto Attribute. Podemos entonces recuperar un o b j e t o ~ tr ti b u t e en particular de un o b j e t o ~ t t r i b u t e s :


Attribute

a t t r

ar.getl"cn");

Servicios de directorio v JNDI


Llegados a este punto, deberiarnos enfatizar que, aunque recuperar un conjunto concreto de atributos de una entrada particular es rnuy ripido, n o resulta rnuy prictico para busquedas generales. En una busqueda LDAP general, el usuario final no va a conocer 10s Nornbres Diferenciados existentes de las entradas que esti buscando. Por ello, tendrernos que buscar en un servidor LDAP y recuperar un conjunto de entradas. En J N D I (en oposicion a Netscape Directory SDK para Java), esta busqueda devolveri todos 10s atributos asociados con cada entrada individual. Si realizarnos entonces llarnadas posteriores a getAtt r ibutes ( ) para recuperar un subgrupo corno en el ejernplo anterior, sera necesaria otra llarnada al senidor LDAP y recuperar el subgrupo de atributos. Este procedimiento es ineficiente porque requiere que utilicernos rnernoria extra para todos 10s atributos y ancho de banda extra para la cornunicacidn extra. La rnemoria extra es necesaria porque nuestra aplicaci6n debe rnantener 10s datos de 10s resultados de la busqueda LDAP para nosotros 10s procesemos. Para rneiorar el rendirniento en nuestras aolicaciones Tava. debernos reducir el volurnen de rnernoria aue utilizarnos porque el recolector de residuos de JVM puede tardar en reaccionar, o disrninuir notablernente el ritrno de la aplicacion, ya que reclama rnis mernoria. A rnedida que rnejora la capacidad del recolector de residuos y se reduce el precio de la mernoria, puede que lo utilicernos sin pensirnoslo dos veces. Sin embargo, existe otra irea potencial de problemas y se trata del hecho de que requiere que utilicernos multiples conexiones de red, alli donde s610 habriarnos utilizado una bajo un nivel rnis bajo de API LDAP.
d ,

Esto no significa que no debarnos utilizar JNDI, sino que debemos cornprender las irnplicaciones de su uso. Tarnbien podernos utilizar J N D I para adadir nuevas entradas a1 senidor, elirninar entradas y rnodificar las entradas existentes. A continuacidn, exarninarernos estas operaciones.

Utilizar J N D I para aiiadir entradas a un senidor LDAP resulta, de hecho, rnis dificil que con otros SDK de LDAP. Esto se debe a que el objetivo primordial de J N D I es leery escribir objetos Java en la red. Una adicionales, corno crear una clase Java consecuencia de esto es que un programador debe saltar obsticulo~ para cada tipo de entrada que quiera afiadir a1 senidor LDAP. Aqui estudiarernos corno aiiadir y rnodificar una simple entrada en el senidor LDAP pero rnis adelante, en este rnisrno capitulo, aprenderernos c6mo utilizar el senidor LDAP corno rnernoria de un objeto. Para alrnacenar una entrada en un senidor LDAP utilizando JNDI, debernos asociar un objeto a un Nornbre Diferenciado (DN). Esto significa que cada objeto que alrnacenarnos en el senidor (ya sea una sencilla entrada de persona o una clase Java serializada) debe tener un D N asociado. Recuerde que un D N es el nombre exclusivo que debe poseer cada entrada en un senidor LDAP. Si carnbiarnos a un senicio de directorio diferente (corno NDS), todavia ser6 necesario contar con un nornbre exclusivo para cada objeto. Si todo esto le parece excesivo, so10 recuerde que se convertiri en algo secundario con el tiernpo y que hacernos esto (proporcionar un nornbre exclusivo) cada vez que guardarnos un archivo en el disco duro. Ningun archivo del sistema de archivos puede cornpartir nornbre con otro archivo. Si querernos tener dos archivos con el nornbre miarchivo. txt, debernos guardarlos en directorios diferentes de nuestro sisterna de archivos; de lo contrario, una version borrari a la otra. Para alrnacenar incluso una simple entrada en el senidor LDAP, debernos crear una clase que irnplernente la interfaz DirContext. Esta interfaz define cdrno debe ser alrnacenado el objeto (ya sea una persona o una clase Java serializada) en el senidor del directorio y recuperada del senidor. Por ejernplo, si tiene un objeto Person,su clase especificari cdrno construir su D N , cdrno almacenar 10s atributos disponibles (por ejemplo, nombre cornpleto, direccidn de e-mail, nurnero de telkfono, I D de usuario, contraseria, etc.) y proporcionar varios rnecanisrnos para rnanejar 10s datos recuperados. La interfaz DirContext tarnbikn proporciona muchas forrnas sofisticadas de rnanejo de datos y es la interfaz bisica para construir un proveedor de senicios de directorio.

Capitulo 2
Del mismo modo que con cualquier otro DSK LDAP, una operaci6n de adici6n solamente puede ser ejecutada por un usuario autentificado con derechos para aiiadir una nueva entrada en el servidor. Los ACL de LDAP pueden ser configurados de modo que 10s usuarios s61o puedan aiiadir entradas en determinadas partes del irbol de directorio. Nuestra siguiente muestra de c6digo presenta una clase P e r s o n muy sencilla que implements la interfaz D i r C o n t e x t . La mayoria de 10s metodos de la interfaz no estin verdaderamente implementados (except0 ; ' para capturar excepciones) porque no 10s necesitamos en este ejemplo tan sencillo. Observe que esta clase se 'deriva del ejemplo D r i n k . j ava encontrado en el tutorial de JNDI (http://java.sun.com/products/jndi/tutorial). Los metodos que implementamos aqui, g e t A t r i b u t e s ( ) y el constructor, nos permiten almacenar/ recuperar 10s datos en una clase Person como entradas LDAP tradicionales. El resto de 10s metodos que no implementamos por completo son utilizados primordialmente para construir proveedores de servicios completes. En su lugar, simplemente capturamos excepciones aiirmando que no nos ajustamos a1 servicio concreto. Los nuevos objetos tambikn deben conformarse a1 esquema del servidor LDAP; de otro modo, las entradas no serin aiiadidas. Resultari mis ficil explicar como aiiadir una entrada con J N D I si explicamos en el c6digo a medida que vamos avanzando. Una vez mis, observe que el c6digo fuente completo de este ejemplo esti disponible para su descarga en la pigina Web de Wrox. En primer lugar, nuestra declaraci6n de clase. Fijese en que explicamos que implementaremos 10s mktodos para la i n t e r f a z D i r C o n t e x t :
import j a v a . u t i l . + ; import j avax. naming . + ; import javax. naming .directory.+; public class Person implements DirContext String type; Attributes myAttrs;

A continuaci6n, tenemos nuestro constructor. Este constructor toma varias cadenas que utilizaremos para construir una clase de objeto i n e t o r g p e r s o n :
public Person(String uid, Strinq givenname, Striri'g sn, String ou, String mail) { type = uid;

Utilizaremos la clase B a s i c A t t r i b u t e s para ahacenar nuestros atributos y sus valores. A1 especificar t r u e en el constructor Bas i c A t t r i b u t e s estamos indicindole que ignore el caso de nombres de atributos a la hora de realizar bGsquedas de nombres de atributo:
myAttrs
=

n e w BasicAttributes (true);

Para aiiadir un atributo multivalor, necesitamos crear un nuevo objeto Bas i c A t t r i b u t e , que requiere el nombre del atributo en su constructor. Aiiadimos entonces 10s valores del atributo con el metodo a d d ( ) :
Attribure o c = n e w BasicAttribute ("objectc1ass"); oc. add ("ir~etOrgPersoi-1") ; oc. add ( " o r q a n i z a t i o r ~ a l P e r s o r ~ ;" ) oc.add("person"); oc.add("top"); Attribute ouSet = new BasicAttribute("ouW); ouSet.add("People"); ; ouSet .add ( o u )

Servicios de directorio v JNDl


+
" " + sn;

String cn

givenname

Finalmente, aiiadimos todos nuestros atributos a1 objeto B a s i c A t t r i b u t e s :


myAttrs .put ( o c ) ; myAttrs.put (ouSet); myAttrs.put("uidW, uid); myAttrs.put ("cn", e n ) ; myAttrs.put ("sn", sn); myAttrs. put ("givenriame", givenname) ; myAttrs.put ("mail", mail);

C u a n d o g e t A t t r i b u t e s ( ) es Ilamado, devuelve nuestro o b j e t o ~ a s i c ~ ri tb t u t e s cuando es solicitado por un nombre en forma de cadena. Esti diseiiado para devolver hicamente 10s atributos de una entrada especifica pero, puesto que esta clase s61o albergari una entrada, no va a ser Ilamada. Presentamos una manera de implementar si fuera del siguiente modo:
publlc Attributes getAttributes(Strir13 name) thruws NamingException if ( ! name. equals ( " " ) ) { throw r~ew N a m e N o t F o u r l d E x c e p t l o n i i ;
{

I
return myAttrs;

1 Este mttodo tiene la misma funci6n que el primer g e t A t t r i b u t e s ( ) per0 s61o es invocado cuando el nombre ha pasado el objeto Name:
public Attributes getAttributes (Name name) throws NamirigException return getAttributes (name. tostring ( ) ) ;
{

I
El siguiente mttodo devuelve unicamente 10s atributos enumerados en la matrizd String ids. El nombre String deberia ser un DN:
public Attributes getAttributes(String name, String[] i d s ) throws NaminqExceptior~ { if ( ! name.equals("")) { throw n e w NameNotFoundExceptioni) ; 1 Attributes answer = new BasicAttributes ( t r u e ) ; Attribute target; for (irk i = 0; i < ids.length; i t + ) { target = rnyAttrs.get (ids[i]) ; if (target ! = null) { answer.put(target);

I
1 returrj ar~swer;

I
Esta implementaci6n es similar a ]as de otros mttodos g e t A t t r i b u t e s ( ) , except0 en que toma un objeto~ame:
public Attrioutes getAttributes ( N a m e name, String [ I throws NamingExceptiori { ids)

Caoitulo 2
return g e t A t t r i b u t e s (name. t o s t r i r ~ q ( ), ids);

I
El metodo t o s t r i n g ( ) es utilizado para la codificaci6n:
public String tostring ( return type;
)

Finalmente, las siguientes lineas se utilizan para implementar metodos que un proveedor de servicios

JNDI (como la clase I n i t i a l D i r C o n t e x t ) utilizaria para proveer a una aplicaci6n de semicios tales
como lectura de entradas desde el directorio o la autentificaci6n a1 servidor:
//
No u t i l i z a d o p a r a e s t e e j e m p l o p u b l i c O b j e c t l o o k u p (Name n a m e ) t h r o w s N a m i n g E x c e p t i o n t h r o w new O p e r a t i o n N o t S u p p o r t e d E x c e p t i o r ~ ( ) ;
{

1
p u b l i c O b j e c t l o o k u p ( S t r i r i g name) t h r o w s N a m i n g E z c e p t i o n t h r o w new OperationNotSupportedException ( ) ;
{

I
p u b l i c v o i d b i n d ( N a m e name, O b j e c t o b j ) t h r o w s t h r o w new O p e r a t i o n N o t S u p p o r t e d E x c e p t i o r ~ ( ) ; NamingException
{

I
El c6digo fuente completo para este ejemplo y para todos 10s ejemplos de este libro esti disponible para su descarga en http://www.wrox.com/ o en http://www.AnayaMultirnedia.es. A continuaci6n, demostramos la clase J N D I A ~ j~ a v a , que utiliza la clase P e r s o n , desarrollada anteriormente, para ahadir una entrada de Mark Wilcox a1 servidor LDAP (ya hemos visto gran parte de este c6digo) :
import import import import public java.util.Hashtable; j a v a . u t i l . Enurneratior!;

ja v a x . n a m i n g . * ; javax.naming.directoryYi;
class JNDIAdd
{

/ / Implementacihn d e contexto p u b l i c s t a t i c S t r i n g INITCTX


public public public public

irllcial "corn. s u n . j r ~ d i l .d a p . LdapCtxFactoryW;

s t a t i c S t r i n g MY-HOST = " l d a p : / / l o c a l h o s t : 3 8 9 " ; = "uid=kvaughan, ou=People, s t a t i c S t r i r ~ g MGR-DN s t a t i c S t r i n g MGR-PW = " b r i b e r y " ; s t a t i c S t r i n g MY-SEARCHBASE = " o = A i r i u s . corn";

o=airius.cornW;

p u b l i c s t a t i c void main(Strir1g a r q s [I ) { try i / / H a s h t a b l e p a r a i r ~ f o r m a i c b n d e l medio H a s h t a b l e e n v = new H a s h t a b l e ( ) ; / / E s p e c i f i c a r qu6 c l a s e u t i l i z a r p a r a rluestro

proveedor

JNDl

~ ~ ~ . ~ U ~ ( C ~ ~ I ~ ~ X ~ . I N I T I A L ~ ~ C O NI N T IE TX CTX ~)F ; ACTORY,


e r ~ v . p u t ( C o n t e x t . P R O V I D E R e n v . p u t i C o n t e x t . P R O V I D E R _ U R L , M Y H O S T I ; U R L , M Y Y H O S T ) ;
e n v . p u t ( C o r ~ t e x tS.E C I I R I T Y Y A U T H E N T I C A T I O N , " s ~ m p l e " ; e r l v . p u t ( C o n t e x t . SEC~JRITYYPRINCIPAL,14GRRDN) ;

e n v . p u t ( C o n t e x t . S E C U R I T Y e n v . p u t i C o n t e x t . S E C U R I T Y C R E D E N T I A L S , M G h P C R E D E N T I A L S , M G ~ h P W ) ;

Servicios de directorio v JNDl


//

O b t e n e r una DirContext c t x Person p


=

r e f e r e n c i a p a r a un c o n t e x t o d e new I n i t i a l D i r C o n t e x t ( e r h v ) ;

directorio

new

P e r s o n ( " m e w i l c o x " , "Mark", "Wilcox", "ou=Accounting", "mewilcox@airius. corn") ; p);

c t x . b l n d ( " u i d = m e w l l c o x ,o u = P e o p l e , o = a i r i u s . o m , catch(Exceptior1 e ) { e.printStackTrace ( ) ; S y s t e m . e x i t ( 1 );

I
I
1

En primer lugar, debernos crear un nuevo objeto Java que irnplernente la interfaz DirContext igual que nuestra clase Person del siguiente rnodo:
Person p
=

new

Persori("rnewilcox", "Mark", "Wilcox", " o u = A c c o u r ~ t i n y " , " r n e w i l c o x @ a i r i u s .corn") ;

Entonces asociarnos un nornbre (especificarnente el D N de la entrada) a este objeto en nuestro contexto actual con el metodo bind ( ) de la interfaz DirContext del siguiente rnodo:
c t x . b i n d ~ " u i d = r n e w i l c o x , o u = P e o p l e ,o = a i r i u . c o r n , p);

La interfaz Ini tialDirContext realizari una operation de adicion LDAP. Tornari todos 10s atributos que hernos situado en nuestra clase Java y 10s codificari para su transferencia a un servidor LDAP. Corno hernos utilizado la clase BasicAttributes para construir nuestros atributos, Cstos serin alrnacenados/recuperados corno datos LDAP estindar y no corno puros objetos Java. Esto significa que si alrnacena sus datos LDAP de este rnodo, cualquier otro cliente LDAP, independienternente de que estC escrito en C , Per1 o Visual Basic, todavia podri acceder a ellos. DespuCs de cornpilar y ejecutar con Cxito nuestros archivos de clase Person. j ava y JNDI .j ava, podernos ver el resultado exarninando nuestro directorio airius .corn del servidor Netscape Directory Server. En 61 deberiarnos poder ver nuestra nueva entrada:

i M d W & Tyler

Pee TY(Cr

A Leurrh A Randy Uhch A Jell Vnu$m A UrstmVcq#Im

+ MahwvA Andy

A Jell v ~ d ~ r

w*o

C BTsJWa*?r

A b w Walrcf A Jomwsr A CecsW s b x a ~uqwtvace A DaWWd


iEncwad

C ~

c u s A 7obaW d A PJanwc

Haciendo doble clic en el nombre destacado, podemos comprobar que todos nuestros detalles han sido afiadidos de acuerdo con nuestro c6digo:

Mark Wilcox
People

Phone: Fax:

user
Licenses

Frst Name

'Lad Name: 'Cwrmon Name@!


'Userl).
P~~FFIo(~~
Conlim Pesswct

Lanwm

E-Mslt
Phona

Fax

Arcess Pcrlnlssbns Help

Advanced ..

OK

Cacel

Help

Servicios de directorio v JNDI

Modificar una entrada


Tan pronto como afiada una entrada a un servidor LDAP, necesitari modificarla. Los motivos pueden ser diversos, incluido un cambio en la contraseria de usuario, la actualizaci6n de la configuraci6n de una aplicaci6n, etc. Las modificaciones realizadas a una entrada se hacen con las clases Modi f i c a t i o n 1t em y Bas icAtt r ibut es. Cuando realizamos una modificaci6n, h a puede ser de tipo A D D (ariadir), REPLACE (reemplazar) o DELETE (borrar). La modificacion REPLACE ariadiri un atributo si 6ste no existe todavia.

Tambikn debemos ser conscientes de que si realizamos un reemplazamiento en un atributo que tiene multiples valores sin enviar 10s valores extra junto con nuestro valor de reemplazamiento, todos 10s valores s e r h eliminados.
--

Una vez mis, las modificaciones deben ser realizadas por un usuario autentificado y tales modificaciones" que pueden realizarse estarin determinadas por 10s derechos que la entrada asociada tiene sobre una entrada determinada. Por ejemplo, 10s usuarios pueden generalmente cambiar sus contraseiias per0 no pueden cambiar nada mis, mientras que 10s asistentes administrativos normalmente pueden modificar n~meros de tel6fono y direcciones de correo. Normalmente se necesita un administrador de bases de datos para realizar tareas tales como cambiar un I D de usuario. El c6digo que se muestra a continuacih muestra c6mo podemos modificar 10s atributos de la entrada de Mark Wilcox que aiiadimos en el ejemplo anterior:
~rnportjava.utl1 .Hashtable; import j ava. u t i l . Enu~neratior~; import import public

'

--

j a v a x . n a r r ~ i r c q .' ;
j avax. r~amir~g.directory * ;.

class

JNDIMod

/ / Implernentaci6n d e c.jrjte,.ti p u b l i c s t a t i c S t r i n g IIIITSTX


public public public public public tiy s s s s t t t t a a a a t t t t i i i i c Strinq c String c String c String

inicial
=

"com.sun.jr~di.1dap.LdapCtory";
o=airius.

MY-HOST = "ldap://localhost:389"; "uid=kvaughan, su=People, MGR-DN MGR-PW = " b r i b e r y " ; M Y -SEARCHBASE = " o = A i r i u s . c o m " ;

LXIII";

static

v ~ i dr n a i n ( S t r i r 1 q

args[]) {

//

H a s h t a b l e par a l n f ~ r m a c l h n d e l H a s h t a b l e env = new H a s h t a b l e i ) ;

medlo

//

E s p e c i f i c a r que c l a s e u t i l i z a r para n u e s t r o proveedor e n v . p u t ( C o n t e x t . I N I T I A L ~ C 0 N T E X T T F A C T O P P P f ,INITCTX) ; env. put erl.J.put erjv. p u t env. put

JNDI

( C o n t e x t . PROVIOER URL, M Y HOST) ; ( c o n t e x t . SECIJRIT<AUTHENTICATION, usimpleu ; ( C o n t e x t . SECURITY-FRINCIPAL, MGR-DN) ; ( S o n t e x t . SECURITY-CREDENTIALS, MGR-FW) ; una ctx r e f e r e n c i a p a r a un c o n t e x t o d i r e c t o r i o rlew I n i t i a l D i r C o n t e x t ( e r ~ ' ~ ) ;

//

Obtener DirContext

Capitulo 2
ModificatinnItem[] mods Attribute mod0 Attribute modl mods [O] mods [I]
= =
=

new Modificatior,Item[2] ;

new BasizAttribute ("telephor~er~umber", "940-555-2555"); new RasicAttribute("l", "Waco");

new Modificatior~Item(DirContext.REPLACE ATTRIBUTE, mod0) ; new ModificatioriItem( DirContext .ADD ATTRIBIJTE, mod1 ) ;

/ / DirContext. DELETE ATTRIBUTE not showr, here ctx.modifyAttriljutes("uid=mewi~zox,nu=Peop?e,o=airius.com", m o d s ) ; catch(Exception e ) [ e.printStackTrace ( ) ; System.exit ( 1 ) ;

Para rnodificar una entrada utilizarnos la c ~ a s e ~ o d i f i c a t i o n ~ La tem c~ase~odification~temtorna un tipo de modificaci6n (por ejernplo ADD, REPLACE o DELETE) y un objeto A t t r i b u t e como B a s i c A t t r i b u t e . ~ s t es e un ejernplo que nos perrnite afiadir un nuevo atributo, localidad (el atributo l ) , con un nuevo valor de "waco" en la entrada:
Attribute modl = new RasicAttribute ("l", "Waco") ; m o . 3[l ~ j = new Mo~3ificationItemlPirContext .ADLl-ATTRIBUTE, modl) ;

La rnodificacion real es realizada por el mCtodo D i r C o n t e x t , m o d i f y A t t r i b u t e s tenernos un ejernplo de este proceso:

()

. A continuaci6n,

ct:i.modif yAttributes ( " ~ ~ i d = m e w i l c ~ou=People,o=airius. ;x, corn", mods) ;

Una vez mls, se modifica la entrada en un sewidor LDAP utilizando LDAP tradicional y no corno objeto de mod0 que cualquier otro cliente puede todavia acceder a estos datos. Esta vez, cuando examinemos la entrada de Mark Wilcox en el Senidor Directorio y hagarnos clic en A d v a n c e d ...p ara obtener una visi6n detallada, verernos que el ncmero de teltfono y la localidad han sido afiadidos a1 directorio:

Servicios de directorio v JNDl

File

Edit

View

.--

- .

-.

. .

Email address First name Full name

I mew~kox@air~us.com
1 Mark 1Msrk Wllcox

~ a sname t lw~lcox

Object class

1 organizationalPerson
person

Organizational Unit

1ou=Accounting
) mew~lcox
OK

I
I

Telephone number 1930-555-2555 User ID

I
Eliminar una entrada

Cancel

Help

Finnlmente, necesitari eliminar las entradns de su servidor LDAP. Esto s e consigue ficilmente invocando el n1Ctodo des t rovcontext ( ) de la interfaz Dircontext. con el nombre diferenciado d e la entrada que necesita ser climinada. Normalmente, las operaciones de borrado estln restringidas a los administradores de bases de datos LDAP. kste es nuestro ejemplo modificado para eliminar una entrada:

Capitulo 2

public

static

S~L-irig MY-ENTRY

"uid=mewilcox,

o u = P e o p l e , o=ai r i u s . com";

p u b l i c s t a t i c ;/(?id mail~l!Strirlg a r g s [ ] ) { try i / . ' H a s h t a b l e p a r a i n f o r m a c i S n d e l medio H a s h t a b l e erlv = r~tew H a s h t a b l e ( ) ;

//

O t i t ? r ~ e r una D i r C ~ > r j t e x tc t x

~ ? f e r e r t c i a paL-3 un c o n t e x t o d e rlew I n i t i a l D i r C o r , t e x t (env) ;

Jirectorio

c t x . J e s t r o b - S u b c o n t e x t ( M Y -ENTRY) ; catrh(Exception e ) { e.printStackTrace ( ) ; System.txit(1);

La unica diferencia real del c6digo de este ejemplo es esta linea:

Por ello, despuks de compilar y ejecutar este programa, borrari nuestra entrada del servidor LDAP Hasta aqui, esto ha sido un vistazo a vuela pluma sobre LDAP. Si quiere mis informacidn existen un gran n6mero de fuentes. Wrox Press ha dedicado por completo un libro a este tema, Implementando LDAP 71por Mark Wilcox, ISBN 1-261002-21-1, o bien puede consultar la Web del GurG de LDAP en la direcci6n http://www.Idapguru.com/

Almacenar y recuperar objetos Java en LDAP


Uno de 10s atributos mis importantes de JNDI es su capacidad para utilizar la red como almacin de objetos. Esto significa que podemos utilizar la red para compartir objetos Java con versiones distribuidas de una aplicaci6n o con aplicaciones dispares. Por ejemplo, podriamos crear una clase que calcule el impuesto de venta sobre un articulo. Este tip0 de clase podria ser utilizado potencialmente por nuestro departamento de ventas para crear 6rdenes de compra y por nuestra oficina de contabilidad para hacer sus cuentas. Podemos utilizar casi cualquiera de 10s proveedores J N D I disponibles para almacenar nuestras clases, pero uno de 10s modos mis Gtiles es utilizar un servidor para que realice este proceso. Existen varias razones por las que preferiria utilizar LDAP como su almacin de datos:
O Ventaja de un recurso centralizado existente

Ventaja de normas abiertas existentes LDAP esti disponible en la red "fuera de la caja" LDAP esti optimizado para un acceso de lectura extremadamente ripido

Servicios de directorio v JNDI


O

LDAP tiene un fuerte sistema de seguridad incorporado

J N D I le permite almacenar diversos tipos de objetos relacionados con Java en el senidor LDAP:
0

Entradas del directorio LDAP estindar Proporciona la capacidad de manipular 10s datos del directorio estindar ( i n e t o r g p e r s o n , g r o u p O f U n i q u e N a m e s , o b j e c t c l a s s e s , etc). Los datos del directorio estindar son de menor tamafio (y, por lo tanto, rnis ficil de acceder y de modificar) y pueden ser compartidos entre diferentes lenguajes. La capacidad de mantenerse neutral con respecto a1 lenguaje con datos de directorio es de vital importancia en una gran empresa, donde varios lenguajes diferentes (por ejemplo, Java, C / C + +, Visual Basic, Cobol, etc.) pueden ser utilizados para el desarrollo de programas. Obietos lava serializados , " Nos proporciona la capacidad de almacenar y recuperar objetos Java que han sido serializados (10s obietos actuales Y todas las clases relacionadas Y almacenadas en formato binario) en el senidor LDAP. Probablemente, el formato rnis ficil de utilizar pero tambiCn el que requiere mayor ancho de banda y espacio de almacenamiento. Este formato s610 es comprensible por Java en apoyo a la persistencia de objetos. Los dos usos rnis comunes de objetos Java serializados son 10s objetos EJB y JDBC Datasource. Como ya hemos debatido anteriormenre, las plataformas de procesamiento distribuido como CORBA y RMI utilizan registros para registrar las clases de objetos que exponen. Sin embargo, estos registros no facilitan la capacidad de buscar en ellos y le obligan a codificar la posici6n del senidor en la aplicaci6n. U n objeto R e f e r e n c e de Java permite almacenar datos en el senidor del directorio como referencia indirecta a la verdadera posici6n del objeto. Por ejemplo, podria tener un objeto almacenado en tiempo real en un senidor RMI. En lugar de codificar la posici6n del registro RMI en la aplicaci6n, puede conectar a un senidor LDAP y localizar el objeto " c n = R e a l Time S t o c k Q u o t e " , que contiene el URLRMI para el objeto stock. Esto reduce la necesidad de recompilar la clase cada vez que desplace la clase stock a un registro diferente y facilita la lectura del c6digo.

0 Referencias

La opcion a utilizar para almacenar 10s objetos dependeri de la aplicaci6n que esta construyendo y de como necesita acceder a 10s datos. Estudiaremos estos tres objetos con rnis detalle en las siguientes secciones.

LDAP tradicional
Las organizaciones desearin a menudo acceder a 10s datos del senicio de directorios desde varios clientes utilizando lenguajes diferentes. U n uso muy extendido de un servicio directorio es el de autentificaci6n de usuario. Resulta obvio que almacenar datos de autentificaci6n de usuario en un formato que s61o Java puede utilizar reduce el nhmero de aplicaciones que pueden hacer uso del directorio para autentificacion. Esto, a su vez, aumenta el coste de 1as actividades empresariales porque en ese caso necesita otro servicio de directorio para facilitar senicios de autentificacidn a aplicaciones que no pueden acceder a objetos Java. Algunas aplicaciones n o necesitarin autentificaci6n per0 podrin beneficiarse del listin de direcciones del servicio de directorio. Por ejemplo, su programa de e-mail puede utilizarlo para encontrar la direcci6n de e-mail de compaiieros de trabajo, su departamento de marketing puede utilizarlo para crear cartas de formato fusionado, mientras que 10s desarrolladores Web pueden utilizarlo para crear un portal adaptado a cada usuario. Cada una de estas aplicaciones puede construirse utilizando Java como lenguaje de desarrollo. Fundamentalmente, su compaiiia puede

Capitulo 2
reducir significativamente su sobregasto manteniendo datos constantes sobre sus empleados y sus clientes en una base de datos central. Una de las ventajas de almacenar datos de este mod0 es que es posible tratar cada entrada como un objeto en Java per0 otros lenguajes no tienen por quk estin orientados a objetos para poder acceder a 10s datos.

Java serializado
Sin embargo, si tenemos un numero creciente de aplicaciones Java que necesitan acceder al repositorio central de objetos Java preconstruidos, podemos utilizar la serialization Java para almacenar esos objetos en el senidor LDAP. Entonces, cuando una aplicacion necesita un objeto determinado (por ejemplo, un dispositivo de representacidn 3D), puede recuperarlo del senidor LDAP, s61o cuando sea necesario, y luego recuperarlo. Otra caracteristica positiva es que, a la hora de actualizar el dispositivo de representacibn, todas las aplicaciones que estin utilizando el dispositivo tendrin acceso a la actualizaci6n sin tener que remendar las aplicaciones finales.

Referencias Java
Finalmente, si nos encontramos en un medio dominado por Java, puede que queramos aprovechar las ventajas de las referencias Java. Las referencias reducen 10s requisitos de almacenamiento y ancho de banda para almacenar y recuperar entradas porque no almacenan el objeto completo en el directorio; en su lugar, so10 almacenan componentes clave necesarios para reconstruir el objeto en una clase factoria. C o n frecuencia, 10s componentes almacenados son un U R L que apunta a la verdadera l o c a h a c i 6 n del objeto. Por ejemplo, si creamos un objeto de impresora estindar, podemos construir un P r i n t e r F a c t o r y que puede adoptar 10s siguientes parimetros:
O

Localizaci6n de la red

o Opciones de color (monocromo, en color)


0 E~~ecialidades (postdatas, plotter grifico) O Estado actual (sin papel, on-line)

Estos parimetros pueden ser trasladados a P r i n t e r F a c t o r y y siempre devolverin un objeto P r i n t e r que nuestra aplicaci6n puede utilizar para imprimir. Reduce el ancho de banda y el almacenamiento porque solo es necesario almacenar 10s parimetros anteriores. Resultan mis ficiles de manejar para un programador de aplicaciones porque parte de la referencia es el nombre del paquete completamente cualificado, por lo que no tenemos que incluirlo con nuestra aplicaci6n; s610 necesitamos asegurarnos de que JVM puede encontrar el paquete.

Si desea ma's informaci6n sobre el uso de J N D I y L D A P como almacin de objetos Java, puede dirigirse a la pagina oficial J N D I en http:l/java.sun.com/jndi.

Aunque LDAP es una parte importante de una red de senicios de Internet y, a pesar de que mucha gente utiliza J N D I para poder utilizar LDAP en sus aplicaciones Java, LDAP no es la linica opcidn disponible.

Servicios de directorio y JNDI


LDAP tiene sentido cuando es necesario gestionar information demogrifica que no cambia per0 que, con mucha frecuencia, es necesario acceder a ella muy ripidamente. Sin embargo, hay ocasiones en las que se necesita acceder a datos que no pueden ser almacenados en LDAP, como es el caso de las entradas DNS o Enterprise JavaBeans. Aunque el resto del capitulo se centra en el servicio de nombres de dominio, Domain Naming Service (DNS), debemos sefialar que fuera de LDAP, el lugar en el que utilizaremos J N D I con mis frecuencia es EJB y otros servicios J2EE de un servidor de aplicacion. Veremos algunos ejemplos mis adelante. La raz6n por la que nos centramos en D N S en este momento, en oposicion a una muestra J2EE completa, es que 10s ejemplos de este capitulo esperan demostrar la flexibilidad de J N D I a1 utilizar ejemplos mis sencillos de 10s que seria posible utilizar con EJB.

Ejemplo de aplicacion DNS


Para demostrar como utilizariamos las mismas clases J N D I bisicas per0 con diferentes proveedores de servicios, presentaremos una variation de la aplicacion JNDISearch que ya utilizamos en nuestra secci6n LDAP.

Para esta secci6n se requiere el proveedor de servicios J D N I D N S que se encuentra disponible en Java Developer's Connection y que sera' incluido en J D K 1.4 (ya esta' disponible en la instalaczdn de J D K 1.4 beta). Los archivos relevantes son d n s . j a r y p r o v i d e r u t ils . jar, que deberian localizarse en classpath a1 ejecutar el prograrna.
Tanto LDAP como D N S tienen entradas. A cada entrada se accede mediante un nombre exclusive (en LDAP, es el Nombre Diferenciado, y en DNS, el nombre canbnico). Ambos servicios son construidos en jerarquia; recuerde que ksta es una de las caracteristicas de un servicio de directorio. D N S tiene un mod0 perfectamente definido de construir el irbol (empezando por 10s dominios del nivel superior como .com, .es, .net, seguidos por dominios de segundo nivel como yahoo. com, seguidos por subdominios y anfitriones). LDAP, por otro lado, no tiene reglas establecidas para construir sus estructuras de irbol (por ello encontrari D N S tipo o=Acme Inc, c=US o o=acme . corn o dc=acme,dc=com). Ambos servicios tienen entradas que contienen atributos con uno o mas valores. LDAP tiene clases de objetos que pueden definir diferentes tipos de entradas. D N S so10 contiene entradas en referencia a anfitriones de Internet. LDAP tiene un potente modelo de seguidad basado en autentificacion; DNS no lo tiene. Ya hemos examinado 10s fundamentos de esta aplicacion anteriormente, por lo que no invertiremos mucho tiempo explicando 10s detalles. Nos centraremos en las partes especificas de DNS.
import import import import public java.util.Hashtable; java . u t l l . Enumeratior~; j a v a x . naming. *; ja v a x . naming . d i r e c t o r y . class JNDISearchDNS
{
)

*;

public

s t a t i c void

main ( S t r i n g a r g s [ ]

try i //

Hashtable para informaichn d e l H a s h t a b l e eriv = new H a s h t a b l e i ) ;

medio

Capitulo 2
Observe que estamos cambiando nuestra factoria de proveedor de c o m . s u n . j n d i . d n s . L D A P C t x f a c t o r y a c o m . s u n . jndi.dnsContextFactory.Puestoque estamos cambiando nuestra factoria, necesitamos cambiar nuestro proveedor URL asi como cambiar de l d a p : / / a d n s : / / . Los nGmeros 12 9.120.210.252 hacen referencia a la direcci6n I P del servidor D N S con el que nos comunicaremos:
//
E s p e c i f i c a r q u 6 c l a s e u t i l i z a r p a r a n u e s t r o p r o v e e d o r JNDI env.put ("java.narning. f a c t ~ r y ~ i r ~ i t i a l " , " c o m . s u n . j n d i . d n s . D n ~ C 0 n t e ~ t F a ~ t 0 r; y") e n v . p u t ("java.r~arning.provider.ur1", " d n s : / / 1 2 9 . 1 2 0 . 2 1 0 . 2 5 2 / " 1 ;

La variable instancia, d n s - a t t r i b u t e s , contiene la lista de atributos que deseariamos obtener de un determinado host, pero existe garantia alguna de que todos estos atributos estin a nuestro alcance. Por ejemplo, si el servidor no es un servidor de correo, n o tendri registro XM. 0 puede que el administrador DNS n o tenga la informaci6n O S en el campo H I N F O (abajo) por razones de seguridad (si un intruso puede determinar el O S host para una determinada miquina, entonces podria centrar su ataque utilizando herramientas para violar el O S en cuesti6n):
String dns-attributes

[I

"MX", " A " , "HINFO" ]

Aqui obtenemos el objeto inicial D i r C o n t e x t e intentamos recuperar 10s atributos para el host llamado www .u n t edu:

/ / Obtener DirContext Attributes

u n a r e f e r e n c i a p a r a un c o n t e x t 0 d e d i r e c t s r i o c t x = new I n i t i a l D i r C o n t e x t ( e n v ); a t t r s l = ctx.getAttributes("www.unt.edu", d n s -a t t r i b u t e s ) ;

A continuacion, comprobamos que obtenemos algo de DNS. La raz6n por la que podemos no obtener resultados es que puede que no haya anfitriones que coincidan con nuestro hostname en el servidor DNS.
i f
}

( a t t r s l == n u l l ) 1 Systern.out . p r i n t l n ( " h o s t else {

has

none

of

the

speclfled

attributes\nn);

Ahora imprimimos nuestros resultados, utilizando el mismo algoritmo que hemos utilizado antes:
f o r (itnt : = 0 ; z c d n s a t t r i b u t e s . l e n g t h ; z + + ) { Attribute a t t r = a t t r s l .get (dns attributes [z]) ; i f ( a t t r != n u l l ) { S y s t e m . o u t . p r i n t ( d n s a t t r i b u t e s [ : ] t": " ) ; f o r ( E n u r n e r a t i o r , v a l s = a t t r . g e t A l 1 ( ) ; v a l s . h a s M o r e E l e r n e n t s ( ) ;) S y s t e r n . o u t . p r i n t l r ~ ( v a l s . r ~ e x t E l e r n e( n j t) ;

catchiException e ) { e.printStackTrace ( ) ; S y s t e r r ~e . x i t ( 1 );

La captura de pantalla que aparece a continuacion muestra 10s datos que probablemente reciba de DNS:

Servicios de directorio y JNDI

En este ejemplo, hay dos atributos para la entrada D N S que coinciden con www.unt.edu. Hay un registro A que indica la direccion I P del host y hay un registro H I N F O , que afirma que el servidor ejecuta
actunlmente U N I X . C o m o puede ver, el cambio d e prowedores en J N D I resulta realmente ficil.

Resumen
Los servicios de directorio son una parte importante del entorno de servicios en red. Los directorios proporcionan la capacidad para asociar nombres comprensibles (y recordables) para el usuario con la infornlaci6n que 10s ordenadores necesitan procesar (por ejemplo, nombres d e dominio para direcciones I P o nombres cornunes para referencias Java). T a m b i h nos permiten buscar direcciones d e e-mail y asociar permisos para entornos seguros. L D A P nos ofrece u n protocolo de red estindar para comunicar con servicios de directorio, mientras que J N D I proporciona un API estindar para que Java se comunique con LDAP y con servicios de directorio especializados que n o son accesibles via L D A P (como DNS). DespuCs d e esta breve introdi1cci6n a 10s servicios de directorio, J N D I y LDAP, debe tener una visibn general d e 10s principios bisicos y ya pueda aventurarse en su uso a partir de aqui. Continuaremos nuestro viaje a travks d e algunos d e 10s elementos fundamentales d e la programaci6n de empresn en el siguiente capitulo, examinando con detenimiento el procesamiento condicionado por R i i I .

Procesamiento distribuido

El procesamiento informitico distribuido se ha convertido en un tkrmino frecuente en el vocabulario de programaci6n actual. Hace referencia a1 paradigma de diseiio de aplicaciones en el que 10s programas, 10s datos que procesan y las computaciones reales se extienden por la red, bien para aprovechar el poder de procesamiento de multiples computadoras o debido a la naturaleza inherente de una aplicacion que comprenda diferentes m6dulos. RMI (Remote Method Invocation) permite la comunicaci6n objeto-objeto entre diferentes miquinas virtuales Java, Java Virtual Machines (JVM). Las JVM pueden ser entidades distintas situadas en el mismo o en diferentes ordenadores; incluso una JVM puede invocar mktodos pertenecientes a un objeto almacenado en otra JVM. Esto permite a las aplicaciones invocar mktodos de objetos localizados remotamente, compartir recursos y procesar cargas en sistemas. Los mktodos pueden incluso aprobar objetos que una miquina virtual no ha encontrado nunca, permitiendo la carga dinimica de nuevas clases cuando sea necesario. Esta es realmente una caracteristica muy fitil. Si queremos que dos aplicaciones Java se ejecuten en diferentes miquinas virtuales para que se comuniquen entre si, existen otros dos enfoques de base Java ademis de M I :

o Sockets
0 Java Message Service (JMS)

La programaci6n bisica de red con Sockets es flexible y suficiente para la comunicaci6n entre programas. Sin embargo, requiere que todas las partes implicadas se comuniquen via protocolos referentes a aplicaciones, cuyo diseiio es complejo y puede ser susceptible de errores. Por ejemplo, consideremos una aplicaci6n cooperativa, como una sencilla aplicaci6n de chat, por ejemplo: para que participen multiples clientes primer0 necesitariamos diseiiar a l g h tip0 de protocolo y desputs utilizar Sockets para comunicarse en ese protocolo con el servidor. M I , por otro lado, es un sistema distribuido que utiliza Sockets internamente sobre TCP/IP.

Capitulo 3
La diferencia entre RMI y JMS es que en RMI 10s objetos quedan residentes y estin asociados a las miquinas virtuales (aunque 10s argumentos de mktodo y 10s retornos, asi corno 10s stubs, viajan por la red), rnientras que en JMS 10s rnensajes (objetos) viajan asincr6nicarnente por la red desde una JVM a otra.

La arquitectura RMI
Antes de estudiar c6rno funcionan 10s mecanisrnos RMI, definarnos algunos tkrrninos utilizados con frecuencia.

Para citar la especificaci6n, "En el modelo de objeto distribuido de Java, un objeto remoto es un objeto cuyos mitodos pueden ser invocados desde otra miiquina virtual de Java, potencialmente en un host diferente. Un objeto de este tip0 es descrito por una o miis interfaces remotas, que son interfaces Java que declaran 10s mitodos de un objeto remoto. La invocaci6n de mitodos remotos, Remote Method Invocation (RMI), es la acci6n de invocar un mitodo de una interfaz remota en un objeto remoto."
El prop6sito de RMI es crear objetos en distintas JVM y actuar corno objetos locales. La JVM que invoca a1 objeto remoto es conocida norrnalrnente corno un cliente y la JVM que contiene el objeto rernoto es el servidor. U n o de 10s aspectos rnis importantes del disefio RMI esti en su deseada transparencia. Las aplicaciones no saben si un objeto es rernoto o local. Una invocaci6n de metodo en un objeto rernoto tiene la rnisrna sintaxis que una invocaci6n de rnktodo en un objeto local, aunque en el fondo sucede rnucho de lo que alcanza la vista.

En RMI, el tirmino "servidor" no hace referencia a un servidor fisico o a una aplicaci6n sin0 a un finico objeto remoto que tiene mitodos que pueden ser invocados remotamente. De un mod0 similar, el tirmino "cliente" no hace referencia a una miquina cliente sino que en realidad se refiere a1 objeto invocando un mitodo remoto en un objeto remoto. El mismo objeto puede ser tanto un cliente como un servidor.
Aunque obtener una referencia a un objeto rernoto es ligerarnente diferente a obtenerla para objetos locales, una vez tenernos la referencia, utilizarnos el objeto rernoto corno si fuera local. La infraestructura de RMI interceptari autorniticarnente la llarnada del mitodo, encontrari el objeto rernoto y procesari la solicitud remotarnente. Esta transparencia de posici6n inchye incluso recoleccidn de residuos.

A un objeto remoto siempre se accede a travis de su interfaz remota. En otras palabras, el cliente invoca mitodos en el objeto s610 despuis de asignar la referencia a la interfaz remota.
La implernentaci6n RMI es construida esencialrnente a partir de tres capas de abstracci6n:

Capa de Stubs/Skeletons
Esta capa intercepta llamadas de metodo realizadas por el cliente a la referencia de la interfaz y redirige estas llamadas a un objeto rernoto. Es conveniente recordar que 10s stubs son especificos del lado cliente, rnientras que 10s skeletons se encuentran en el lado servidor.
0

Capa de referencia remota

Procesamiento distribuido con RMI


Esta capa maneja 10s detalles relacionados con la interpretaci6n y la gesti6n de referencias realizadas por clientes a 10s objetos remotos. Conecta clientes con objetos remotos que estin siendo ejecutados y exportados en un senidor por un vinculo de conexidn uno-a-uno.
0

Capa de transporte Esta capa esti basada en conexiones TCP/IP entre miquinas de una red. Proporciona conectividad bisica, asi como algunas estrategias de penetraci6n de cortafuego.

El siguiente diagrama muestra estas tres capas, junto con una interrupci6n de la capa de transporte. Las descripciones de la parte derecha representan las capas OSI (OSI esti descrito de forma concisa en http:// www.webopedia.com/rERMOS/OSl. htrnl):

.
I

rnetodo en el

0bjet0 rernoto

.t

Stub

A Capa de referencla
remota

.
I Objeto rernoto

Ii

Capa de apl~caclon,

Skeleton

Capa de presentaclon

Capa de referencla rernota

4L

Capa de seslon

Capa de transporte

Capa de red

,
I

lnterfaz de hardware

lnterfaz de hardware

1
j

Capa de vinculos de datos

Esta arquitectura en capas proporciona una buena flexibilidad de implementacidn sin afectar a la arquitectura de aplicaci6n. Cada una de las capas pueden ser reforzada o reemplazada sin afectar a1 resto del sistema. Por ejemplo, la implementaci6n de la capa de transporte puede ser reemplazada por un distribuidor con el protocolo User Datagram Protocol (UDP) en lugar de TCP, sin afectar a las capas superlores.

A continuacidn, examinaremos algunas de estas capas mis detenidamente.

Capa de Stub y Skeleton


Para conseguir la transparencia de posici6n, RMI introduce dos tipos especiales de objetos conocidos como stubs y skeletons que cumplen las funciones de una interfaz entre una aplicaci6n y el resto del sistema RMI. El prop6sito de esta capa es transferir datos la Capa de Referencia Remota mediante marshaling (disposici6n) y unmarshaling. Marshaling hace referencia a1 proceso de convertir 10s datos u

objetos transferidos en flujo de bytes y desempaquetando, que es el proceso contrario, es decir, convertir el flujo en un objeto o en datos. Esta conversi6n se consigue mediante serializaci6n de objetos. La capa de stubs y skeletons de RMI se encuentra justo por debajo de la apkaci6n en si y esti basada en el modelo de disefio Proxy. En el uso RMI del modelo Proxy, la clase stub desempefia el papel del proxy para la implementacion del servicio remoto. El skeleton es una clase asistente generada por RMI para ayudar a1 objeto a comunicarse con el stub en el vinculo RMI. El skeleton mantiene una conversaci6n con el stub; lee 10s parimetros para la llamada de mktodo desde el vinculo, realiza la llamada a1 objeto de implementaci6n del servicio remoto, acepta el valor de vuelta y graba el valor de vuelta en el stub. Resumiendo, el modelo Proxy fuerza las llamadas de mitodo a travks de un proxy que actua como sustituto, delegando todas las llamadas en el objeto real de mod0 transparente para el llamador original
Detalles espec$cos sobre el diseiio de me'todos proxy estan mks alli del objetivo de este libro, pero pueden encontrarse en Diseiio de Me'todos, Elementos reutilizables de software orientado a objetos Erich Gamma, et. al. ( I S B N 0-201-63361-2) o me'todos en Java: U n catklogo de diseiios de me'todos reutilizables ( I S B N : 0-471333-15-8).

Analicemos ahora 10s stubs y 10s skeletons con mas detalle.

El stub es un objeto del lado cliente que representa (o actua como un proxy para) el objeto remoto. El stub tiene la misma interfaz, o lista de mktodos, que el objeto remoto. Sin embargo, cuando el cliente invoca un mktodo stub, el stub envia la solicitud mediante la infraestructura RMI al objeto remoto (via skeleton), que es el que realmente la ejecuta. El siguiente apartado enumera la secuencia de eventos ejecutados por el stub en detalle:
0 0 0 0

Inicia una conexi6n con la VM remota que contiene el objeto remoto Escribe y transmite (marshaling) 10s parimetros en la VM remota Espera el resultado de la invocaci6n de mktodo Lee (unmarshaling) el valor de vuelta o la excepci6n de retorno Devuelve el valor a1 llamador

El stub oculta la serializaci6n de 10s parimetros del mktodo (10s parimetros deben ser serializables; el paso de parimetros seri estudiado detenidamente posteriormente) y la comunicaci6n en red con el objetivo de presentar a1 llamador un sencillo mecanismo de invocaci6n. En la VM remota, cada objeto remoto puede tener su skeleton correspondiente.

Skeletons
En el lado servidor, el objeto skeleton se encarga de 10s detalles de "posici6n remota" de modo que el objeto remoto no tenga que preocuparse por ellos. En otras palabras, podemos codificar un objeto remoto del mismo que si fuera local; el skeleton aisla a1 objeto remoto de la infraestructura M I . Durante las solicitudes de mitodo remoto, la infraestructura RMI invoca automiticamente el objeto skeleton de mod0 que kste pueda ejercer su poder. A continuaci6n, una enumeracidn de 10s eventos en detalle:
0

Lee (unmarshaling) 10s parimetros para el mitodo remoto (recuerde que estos parametros han sido escritos y transmitidos (marshaling) por el stub en el lado cliente)

o Invoca el metodo en la implementaci6n del objeto remoto

Procesamiento distri buido con RMI


0

Escribe y transmite (marshaling) el resultado (valor devuelto o excepcion) al llamador (que es entonces leido ( ~ n m a r s h a l i n por ~ ) el stub)

El J D K contiene la herramienta rmic que crea 10s archivos de clase para stubs y skeletons. Los detalles sobre rmic puede encontrarlos en el paquete de J D K u on-line en:
http://java.sun.co~j2se/l.3/docsltooldocs/tools. html

Capa de referencia remota


La capa de referencia remota define y se ajusta a la semintica de invocaci6n de la conexion RMI. Esta capa proporciona un objeto j a v a . rmi . server. RemoteRef especifico de JRMP (Java Remote Method Protocol: siguiente secci6n) que representa un descriptor para el objeto remoto. Un Remotestub utiliza una referencia remota para realizar una invocacion de metodo a un objeto remoto.

En J D K 1.2 y versiones posteriores, 10s stubs utilizan un tinico mitodo, invoke (Remote, Met hod, O b j ec t [ ] , 1ong) en la referencia remota para llevar a cabo la escritura y transrnisidn (marshaling) de para'metros, la ejecucidn de mitodo remoto y la lectura (unmarshaling) del valor devuelto.
La implementaci6n Java 2 SDK de RMI atiade una nueva semintica para la conexidn cliente-servidor: objetos remotos activables (como veremos mas adelante). Otros tipos de semintica de conexion tambikn son posibles. Por ejemplo, con multidifusi6n, un h i c o proxy podria enviar una solicitud de metodo a m ~ i l t i ~ l e s implementaciones simultineamente y aceptar la primera respuesta (que mejoraria el tiempo de respuesta y, posiblemente, la disponibilidad). En el futuro, se espera que Sun atiada semintica de invocaci6n adicional a RMI.

Capa de transporte
La capa de transporte realiza las conexiones de red basadas en flujos de datos en TCP/IP entre JVM y e s responsable de configurar y gestionar dichas conexiones. Aunque dos JVM estkn funcionando en la misma computadora fisica, se conectan a traves de su pila de protocolo de red TCP/IP de su ordenador host. RMI utiliza un protocolo de conexion llamado Java Remote Method Protocol URMP) sobre TCP/ IP (una analogia es http sobre TCP/IP).

JRMP esta' especificado en http:lljava.sun.com/productsljd~l.2/docs/guide/rmi/spec/rmiprotocol.doc.html. Es importante destacar que JRMP es espec@o de la "implementacio'n" Sun. Implementaciones alternativas, como BEA WebLogic, NinjaRMI, ObjectSpace's Voyager, etc., no utilizan JRMP pero, en su lugar, utilizan su propio protocolo de conexidn. Sun e IBM ban desarrollado conjuntamente la siguiente versidn de RMI, llamada RMI-IIOP, que estk disponible con Java 2 S D K versidn 1.3 (o por separado). En vez de utilizar JRMP, RMI-IIOP utiliza Object Management Group ( O M G ) Internet Inter-ORB Protocol ( I I O P ) para comunicar entre clientes y seruidor. I I O P tambie'n permite la integracidn con objetos C O R B A .
A partir de JDK 1.2, el protocolo JKMP fue modificado para eliminar la necesidad de skeletons y, en su lugar, utilizar el proceso de reproducci6n para realizar la conexion al objeto de servicio remoto. De este modo, solo necesitamos generar clases stub en implementaciones de sistema compatibles con JDK 1.2 y versiones anteriores. Para generar stubs, utilizamos la opci6n -v1.2 con rmic.

Para una descripcidn detallada de cdmo fue modificado JRMP para eliminar 10s skeletons, consulte las descripciones de CallData, Operation y Hash en la especificacidn JRMP en http://
java.sun.com/productsljd~l.2/docs/guide/rmi/spec/rmi-protocol.doc3. hmtl.

Capitulo 3
La reproduccidn es u n API del paquete j a v a . l a n g . r e f l e e t en J2SE que permite a1 cddigo Java descubrir informacidn sobre 10s campos, mktodos y constructores de clases cargadas en period0 de operacidn y operar sobre ellos.

La capa de transporte RMI esti disefiada para realizar una conexibn entre clientes y servidor, enfrentindose incluso a obsticulos de la red. Aunque la capa de transporte prefiere utilizar mGltiples conexiones TCP/IP, algunas configuraciones de red conciben una Gnica conexi6n TCP/IP entre un cliente y servidor (por ejemplo, algunos navegadores restringen 10s applet a una sola conexi6n de red de vuelta a su servidor host). En este caso, la capa de transporte multiplexa m6ltiples conexiones virtuales en una Gnica conexi6n TCP/IP.
La capa de transporte en la implementacidn RMI actual esta' basada en T C P pero, una vez ma's, una capa de transporte basada en U D P puede ser sustituida en una implementacidn diferente.

Localization de objetos remotos


Hay todavia una pregunta crucial a la que todavia no hemos respondido. iC6mo encuentra un cliente el objeto? Los clientes encuentran servicios remotos utilizando un servicio de designaci6n o de directorio. Esto puede parecer una 16gica circular. iCbmo puede un cliente encontrar el servicio de designacibn? Es sencillo: un servicio de designaci6n o de directorio es ejecutado en un numero de host y de puerto que el cliente ya conoce (por ejemplo, un puerto conocido en un host publico). RMI puede buscar claramente estos servicios diferentes de directorio con Java Naming and Directory Interface (JNDI), que ya ha sido descrito en el capitulo anterior. El servicio de designaci6n RMI, un registro, es un objeto remoto que sirve como servicio de directorio para clientes manteniendo una asociaci6n de nombres tipo Hashtable con otros objetos remotos. N o es necesario tener un Gnico registro en un determinado host fisico. Un objeto es libre para empezar su propio registro. El rendimiento del registro lo define la interfaz j a v a . rmi . r e g i s t r y . R e g i s t r y . RMI incluye una sencilla implementacibn de esta interfaz llamada Registro RMI (la herramienta rmi r e g i s t r y con JDK tambien puede ser iniciada programiticamente). El Registro RMI se ejecuta en cada rniquina que "alberga" objetos remotos y acepta solicitudes de servicios, por defect0 en el puerto 1009. En terminos sencillos, un objeto remoto es asociado a un nornbre en este registro. Siempre que 10s clientes deseen invocar metodos en este objeto remoto, obtienen una referencia a 6ste buscando el nornbre. La bGsqueda devuelve una referencia remota, un stub, a1 objeto. RMI tambien proporciona otra clase, la clase java.rmi.Naming que sirve como punto de interaccibn del cliente con el objeto que sirve de registro en el host para esta b~squeda:

/ Blisqueda reglstro /
-4
Nornbrado

1 Blisqueda.' 1 nornbrado

Procesamiento distribuido con RMI

Es importante n o confundir java.rmi.Naming con el contexto JNDI. Aunque proporcionan 10s mismos servicios, la clase Naming localiza especificamente objetos e n el registro RMI. Sun facilita u n proveedor J N D I para RMI que permite a 10s clientes buscar objetos RMI utilizando u n contexto JDNI. Este registro RMI de base J N D I puede ser descargado desde http:/fiava.sun.corn/productsfindi/ Los mktodos de la clase Naming toman, como uno de sus argumentos, un nombre que es un j ava .lang .st ring formateado como URL. Examinemos estos mitodos y sus d e s ~ r i ~ c i o n e s :

Metodo
Public static void bind (String name, Remote obj) Public static String [ I list (String name) Public static Remote lookup (String name) Public static void rebind (String name, Remote obj)

Descripcion Asocia el ob'eto remoto a un nombre string. El nombre mismo es el lormato MI URL descrito a continuaci6n. Devuelveun array de 10s nombres asociados en el registro. Devuelve una referencia, un stub, para el objeto remoto asociado a1 nombre especifico. Reasocia (disocia el nombre si yaesti asociado y lovuelve a asociar) el nombre especificado si ya est6 en uso en un Nuevo objeto remoto. Esto puede ser peligroso si diferentes aplicaciones utilizan el mismo nombre en el registro per0 resulta util en el desarrollo. Elimina la asociaci6n con el nombre especificado.

Public static void unbind (String name)

Los mktodos en la clase Naming y en la interfaz Registry tienen idknticas firmas y capturan varias excepciones (que estudiaremos en la siguiente secci6n). Hay una serie de acontecimientos que tienen lugar cuando un cliente invoca una busqueda para un determinado URL en la clase Naming. Primero, se abre una conexi6n Socket al host en el puerto especificado (utilizando una factoria de Socket cliente si es necesario). A continuaci6n, puesto que la implementaci6n de registro en el host mismo es un objeto remoto, se devuelve un stub desde el host al registro remoto. Este stub actua como el proxy cliente para el registro. Posteriormente, se realiza la busqueda Regist ry . lookup ( ) en este stub y devuelve otro stub para el objeto remoto que ha sido registrado con k l en el servidor. Finalmente, una vez que el cliente tiene un stub para el objeto solicitado, interactua directamente con el objeto en el puerto al que ha sido exportado. El URL adopta la siguiente forma:
rml: / / < h o s t P n a m e > [ : i r j a m e -s e r v i c e p o r t > ] / < s e r v i c e -r l a m e >

donde:
0 0

host-name es un nombre reconocido en la red de irea local (LAN) o un nombre DNS en

Internet
name-service-host necesita ser especificado s61o si el servicio de designaci6n esti siendo

ejecutado en un puerto distinto del puerto por defect0 1099

service-name es el nombre string al que se asocia el objeto remoto en el registro

Para facilitar este proceso en la miquina host, un programa servidor expone el servicio de objeto remoto ejecutando la siguiente secuencia de eventos:

Capitulo 3
1. Crea un objeto local

2. Exporta ese objeto para crear un servicio de escucha, que espera a que 10s clientes conecten y soliciten el servicio
3. Registra el objeto en el Registro M I con un nombre phblico

El c6digo expuesto a continuaci6n resume estos pasos:


//
C r e a r e l o b j e t o . La e x p o r t a c i 6 n t i e n e H e l l o S e r v e r o b j = new H e l l o S e r v e r ( ) ; lugar en el constructor

/ / A s o c i a r e l o b j e t o a url nornbre e n e l / / i n i c i a d o con a r ~ t e r i o r l ~ d a d


Narning.rebird ( " / H e l l o S e r v e r " , obj
) ;

registro

que

ha

sido

Existe unaclase similar a la clase Naming, j ava . rmi . registry. LocateRegistry, que tienevarios metodos para obtener directamente una referencia al registro y para iniciar el registro. Como ya hemos indicado, iniciar el registro (ya sea mediante la herramienta o programiticamente) s61o consiste en exportar el objeto remoto que implements la interfaz Registry.

El m e t o d o L o c a t e R e g i s t r y .g e t R e g i s t r y (String host) no contacta con el registro en el host sin0 que busca en el host para certificar que existe. Por ello, aunque este metodo di6 resultado, est? no significa necesariamente que un registro sea ejecutado en el host especificado. Unicamente devuelve un stub que puede entonces acceder a1 registro.

JDK tiene una herramienta llamada rmiregistry que inicia el registro en el host con el siguiente
comando:
~ r n i r t q i - t r y J - D j a v a .security.policy=<policy f i l e ,

En cambio, para iniciar el registro con sus valores por defecto:


start rrniregistry

Recuerde que el registro es un objeto que se ejecuta en una JVM. El marcador- J se utiliza para pasar parimetros, como el archivo de politica, a JVM.
Tambikn puede iniciar programaticamente el registro con el me'todo LocateRegistry. createRegistry (int port) o elma'sdetallado Loca teRegistry. crea teRegistry (int p o r t , RMIClientSocketFactory c s f , R M I S e r v e r S o c k e tFa ct o r y ss f).Ambos me'todos devuelven el stub, implementando la i n t e r f a z j a v a . rmi. registry. Registry.

Archivos de politica
Al codigo se le conceden permisos en lo que se denomina archivos de politica. Si buscamos en el directorio % JAVA-HOME% \ j re \l i b \ S e c u r i t y, encontraremos el archivo de politica por defecto para nuestra JVM llamado j ava. policy. Este archivo puede ser editado manualmente o utilizando el programa de herramientas de politica que encontramos en %JAVA-HOME%\bin-directory. Antes de continuar con un ejemplo, nos desviaremos para examinar las excepciones en M I .

Procesamiento distribuido con RMI

Excepciones RMI
C o m o ya hemos mencionado anteriormente, RMI es un sistema distribuido que utiliza Sockets sobre TCP/IP. En este entorno redificado, pueden fallar muchos elementos. Es importante que el cliente conozca de algGn mod0 las excepciones de mod0 que puede manejarlas del mod0 adecuado y asi solventar problemas a medida que vayan surgiendo. Por ejemplo, n o queremos que un cliente espere indefinidamente una entrada en el Socket si la red falla o n o es posible alcanzar el host. Para que el cliente sea consciente de tales condiciones, todo metodo remoto debe lanzar la excepci6n j a v a . r m i . R e m o t e E x c e p t i o n (o una de sus clases superiores como j a v a . i o . I O E x c e p t i o n o j a v a . l a n g .E x c e p t i o n ) . ~ e m o t e ~ x c e p t i o n e n u n a e x c e p c i 6 genericay n hay subclases especializadas que son lanzadas (y capturadas) en condiciones especificas. Estas excepciones estin descritas en la siguiente tabla:

Lanzada por ciertos metodos de la clase j a v a r m i .Naming (concretamente-bind ( ) , r e b i n d ( ) y u n b i n d ( ) ) y metodos de la interfaz ~ ci v ta t i o n ys ~ tem(que estudiaremos en breve ,para indicar ue el llamador no tiene permiso para ejecutar la accidn s o L l t a d a p o r la Iamada del metodo. Lanzada si existe un intento de asociar un objeto en el registro a un nombre que ya tiene una asociaci6n. Observe que esta excepci6n n o es lanzada (en las mismas condiciones) si se utilizarebind ( ) .Sm embargo, el uso de r e b i n d ( ) puede no ser correct0 en todos 10s casos. ConnectException ConnectIOException MarshalException Lanzada si una conexi6n es rechazada el host remoto para una llamada de metodo remoto. Lanzada si una I O E x c e p t i o n tiene lugar durante la realizaci6n de una conexi6n a1 host remoto para una llamada de mitodo remoto. Lanzada siocurreunaj a v a . i o . ~ ~ ~ x c e ~ t i o n d u r laescrituray ante trasmisi6n (marshaling) de la cabecera, argumentos, o valor de retorno de llamada remota para una llamada de metodo remoto. Lanzada si se realiza un intento de invocar un mitodo sobre un objeto que ya n o existe en la miquina virtual remota. Si se lama esta exce ci6n slgnrf~ca que el objeto ha sido recogido por el recolector de resi&os o n o exportado. Suele ocurrir que elcliente o clientes n o consiguen repetidamente renovar sus alquileres k t o s expiran. Si esto ocurre,por ejemplo, la red se obstruye con trifico o falla. Es lmportante tambikn recodar que el stub con el cliente d o es d i d o mientras estivivo el servidor RMI. Si no desea que el objeto remoto sea recolectado como residuo, debe mantenerlo vlvo en el JVM servidor almacenando una referencia a1 objeto de implementaci6n en una variable estitica. Como objeto disponible localmente, n o sera recolectado como residuo nisi uiera incluso en el caso de que 10s clientes Sean ampliamente inalcanza%les. Lanzada si realiza un intento de l o o k u p ( ) (buscar) o u n b i n d ( ) (desasociar) en el registro un nombre que n o tiene ningGn vinculo asociado.

La tabla continua en la pdgina siguiente

Capitulo 3
Excepcidn Descripcidn La super clase c o m h para una serie de excepciones relacionadas con la comunicaci6n que puedan tener lugar durante laejecuci6n de una llamada de mttodo remoto. ServerError ServerException Lanzada como resultado de una llamada de metodo remoto si laejecuci6n del mktodo remoto en la miquina servidor lanza j a v a .l a n g .E r r o r . Lanzada como resultado de una llamada de metodo remoto si la ejecuci6n del metodo remoto en la miquina servidor l a n z a ~ e m oet ~ x c ei o ~nt.

S t u b N o t F o u n d E x c e p t i o n Lanzada si unaclase stubvilidano pudiera ser encontradaparaun objeto remoto a1 ser exportado. UnexpectedException Lanzada si el cliente de una llamada de metodo remoto recibe, como resultado de la llamada, una excepci6n comprobada que no se encuentra entre 10s tipos de excepciones comprobadas declaradas en la clalisula "throws" del mttodo en la interfaz remota. Lanzada si tiene lugarj a v a . n e t . ~ n k n o w n ~ x c e ~ t i o n d u r ala nte creaci6n de una conexi6n a1 host remoto para una llamada de metodo remoto. Puede ser lanzada durante el proceso de unmarshaling (lectura) de 10s parimetros o de 10s resultados de una llamada de mttodo remoto si:
O Ocurre una exception durante la lectura (unmarshaling) de la cabecera de llamada. O Si el protocolo para el valor de retorno no es vilido.
Q Si ocurre una IOException durante la lectura (unmarshaling) de 10s

parametros (en el lado servidor) o en el valor de retorno (en el lado cliente).

Desarrollo de aplicaciones con RMI


Grabar aplicaciones cliente-servidor utilizando RMI conlleva seis pasos fundamentales:
1. Definir una interfaz remota

2. Implementar la interfaz remota


3. Grabar el cliente que utiliza 10s objetos remotos 4. Generar stubs (proxys de cliente) y skeletons (entidades de servidor)

5. Iniciar el registro y registrar el objeto


6. Ejecutar el servidor y el cliente

Estudiemos cada paso desarrollando una sencilla aplicaci6n como ejemplo para obtener experiencia prictica y acelerar la comprensi6n de cada paso.

Procesamiento distribuido con RMI

Definir la interfaz remota


Una interfaz rnanifiesta las operaciones expuestas y el prograrnador cliente no necesita tener conocimiento de la irnplernentaci6n (la interfaz en este caso tarnbitn sirve corno rnarcador para la JVM). Una interfaz rernota, por definicibn, es un conjunto de mttodos que pueden ser invocados rernotarnente por un cliente:
0

La interfaz remota debe ser declarada p6blica o el cliente obtendri un error a1 intentar cargar un objeto rernoto que implernente la interfaz remota, a no ser que el cliente estt en el rnismo paquete que la interfaz rernota. La interfaz rernota debe arnpliar la interfaz j a v a . rrni Cada mttodo debe lanzar una excepci6n j ava . r m i .RemoteException (o una superclase de RemoteException). Si 10s rnttodos rernotos tienen cualquier objeto rernoto corno parirnetros o tipos devueltos, deben ser tipos de interfaces, no clases de implernentaci6n.

E I 0

L I

Observe que la intelfaz j a v a . rmi no tiene rnttodos. Sdlo se utiliza corno un marcadorpor la JVM, de un modo similar a corno la intelfaz j a v a . i o . s e r i a1 i z abl e es utilizada para marcar objetos corno serializables.
Para nuestro ejemplo, definirernos nuestra interfaz rernota de este modo:
public interface HelloInterface extends java.rrni.Rernote
{

/ / E s t e m6todo e s l l a r n a d o p o r c l i e n t e s r e m o t o s y e s l m p l e m e n t a d o / / p o r e l o b l e t o rernoto. p u b l i c S t r l n g sayHello ( ) throws j a v a . rmi.RernoteExcept~on;


i
--

Si su objeto implementa otras interfaces, manthgalo separado de la interfaz Tambiin puede reducir a1 minimo el numero de objetos registrados en el registro con un modelo de diseiio Factoria o con un unico objeto factoria.

lmplementar la interfaz remota


La clase de implementaci6n es la clase real que proporciona la irnplernentaci6n para mttodos definidos en la interfaz remota. Java. rmi .server. RemoteObj ect arnplia la funcionalidadproporcionadapor la clase j ava. 1ang.Object en el dominio rernoto ignorando 10s rnttodos equals ( ) , hashcode ( ) y tostring ( ) .

Recuerde que elgentrico j ava .rmi .server. RemoteObj ect es una claseabstracta y describe el funcionamiento de objetos rernotos.
La subclase abstracta j a v a rmi .server. RemoteS erver describe el funcionamiento asociado con la implernentaci6n del servidor y proporciona la semintica bisica para ajustarse a referencias rernotas (por ejernplo, crear, exportar a un puerto deterrninado, etc.).
Java.rmi .server. Remoteserver tienedos subclases:

O 0

j a v a . r m i . s e r v e r . U n i c a s t R e m o t e O b j e c t : defineunobjetorernotonoreplicadocuyas referencias s61o son vilidas rnientras esta el sewidor estk activo. j a v a . r m i . A c t i v a t i o n . A c t i v a t a b l e : claseconcretaquedefineelfuncionarnientopara instanciado a solicitud d e objetos rernotos (vkase secci6n posterior sobre activaci6n).

El siguiente diagrarna rnuestra las dos subclases y sus. rnktodos contenidos en relaci6n con la clase

<<lnterface>>i Remote (from rml)


-

Remote Object

Actlvatable (from Actlvat~on) UnlcastRemoteObject (from server)

Remote Server (from server)

U n objeto puede presentar funcionarniento rernoto corno resultado de 10s siguientes factores:
0

La clase arnplia j a v a . r m i . R e m o t e s e r v e r o una de sus subclases (incluidos otros objetos rernotos). Sin embargo, la clase debe invocar u n o de 10s constructores superclase de rnodo que pueda ser exportada. La clase se exporta a si rnisrna explicitarnente pasindose a si rnisrna ( " t h i s ") a diferentes forrnas dernktodos ~ n i c a s t ~ e m o t e ~ b j e ec xp t .o r t o b j e c t ( ) .

El tkrrnino "exportar" encierra la serna'ntica que irnplica la capacidad de u n objeto rernoto para aceptar solicitudes. Esto conlleva escuchar en u n Socket (servidor) TCP. Observe que rnriltiples objetos pueden escuchar en el rnisrno puerto (viase la seccidn sobre Sockets para rna's inforrnacidn).

Procesamiento distribuido con RMI


Ademis de istas, la clase debe implementar una o mis interfaces remotas que definen 10s mitodos remotos.

Una clase remota puede definir cualquier mktodo pero s61o 10s mktodos en la interfaz remota pueden ser invocados remotamente.
La clase de implernentacion de objeto remoto H e l l o S e r v e r para nuestro ejemplo es del siguiente modo:
import import import import public java.io.*; j ava. rmi. * ; j ava. rmi. server . + ; java.util.Date; class HelloServer extends Ur~icastRemoteOb]ect implemerlts HelloIrlterface [

public Helloserver() throws RemoteEzception ( super(); / / Llamar a1 coristructor superclase para exportar este objeto

I
public String sayHello ( ) throws RemoteExcept lor1 ( return "Hello World, the current system time is "

new D a t e ( ) ;

Observe que el cddigo fuente para este ejemplo (y para todos 10s ejemplos de este libro) esta' disponible para su descarga en h t t p : / ~ . w r o x . c o m .y en http://ww.AnayaMultimedia.es.

Grabar el cliente que utiliza 10s objetos remotos


El cliente realiza una bcsqueda en el registro en el host y obtiene una referencia al objeto remoto. Recuerde que es de vital importancia difundir a la interfaz remota. En RMI, 10s clientes siempre interactcan con la interfaz, nunca con la implementaci6n del objeto:
import j ava. rrni . * ; public class Helloclient

public static void rnainistring args[]) [ if ( S y s t e m . g e t S e c u r i t y M a r ~ a g e r ( ) == null) { System.setSecurityManager(new RMISecurityManager());

1
try I HelloInterface obj = (HelloInterface) Naming.lookup("/HelloServer"); String message = obi .sayHello ( ) ; System.out.println(message); 1 catch (Exception e) [ Systern.out .prlntln("HelloClient exception: " +e);

I
1

Capitulo 3

Generar stubs y skeletons


Ahora que tenemos la interfaz remota y las irnplementaciones, podemos generar stubs y skeletons (o s610 stubs en Java 1.2) con la herramienta rmic despuks de haber compilado las clases. N o olvide configurar el directorio desde el que esti trabajando en su ruta de clase; despuks puede utilizar la siguiente linea en una ventana de comando:
rmic v 1 . 2 HelloServer

Observe yue el indicador -vl . 2 suprime la generacidn de skeletons.

Registrar el objeto
Ahora que ya tenemos la interfaz y la implementacibn, necesitamos poner este objeto a disposition de 10s clientes asociindolo a un registro. Esto permitiri a 10s clientes buscar el objeto en el host por un nombre String. Los stubs y 10s skeletons (si es que hay alguno) son necesarios para el registro. Despuks de todo, es el stub objeto el que va a ser pasado desde el registro a 10s clientes.
Con frecuencia se Cree err6neamente que el objeto debe estar asociado a un registro para ser utilizado. En realidad, esto n o es cierto. El objeto esti disponible para su uso en el momento en que es exportado con kxito. Puede funcionar como cliente, invocar un metodo en otro objeto y pasarse a otro objeto.

El siguiente c6digo muestra c6mo registramos nuestro objeto:


import j ava. rmi . * ; public class RegisterIt

~ ~ u b l i static c void main (String args [ I ) { try 1 / / Instanciar el objeto HelloServer obj = n e w HelloServer ( ) ; System.out .printlr~ ("Object instantiated: Naming. rebind ("/HelloServer", o b j ) ; System.out .println ("HelloServer bound 1r1 } catch (Exception e ) ( System.out.prlntln(e);

"

obj )

registry") ;

I I I
Existen dos mktodos en la clase j a v a . r m i .Naming que pueden asociar un objeto en el registro:
0 0

El mktodo b i n d ( ) asocia un objeto a un nombre cadena (string) y lanzar una excepcih ja v a .r m i . ~ l r e a d y ~ o u n d ~ x ci e on p st; laasociaci6n yaexiste El mCtodo r e b i n d ( ) , como ha sido utilizado anteriormente, sustituye cualquier asociaci6n existente por una nueva

El registro debe estar siendo ejecutado para que el objeto se asocie. Puede ser iniciado por la herramienta programiticamente, como ya hemos explicado. Iniciamos el ejecutable con la siguiente linea de comando:
rmiregistry J-Djava.seci~rity.policy=registerit.policy

Procesamiento distribuido con RMI


La politica de seguridad es necesaria debido al modelo de beguridad de Java 2. El registro necesita perniisos para abrir Sockets (un Socket e n un extremo de una conexibn T C P ) que e s t i n restringidos a extensiones estindar en el archivo d e politica p o r defecto. N u e s t r o archivo de politica para este ejemplo, registerit .policy,concede todos 10s permisos:
grant 1 / / P e r r n i t t tvdo p o r a h o r a p e r m i s s i o n j a v a . securit y .A1 1 P r r m i r i ' i o r i ;
; #

Naturaln~ente,n o utilizariamos esta politica e n un e n t o r n o de produccibn. P o r defecto, hay un 6nico archivo d e politica del sistema y un ilnico archivo de politica de usuario. El archi\;o de politica de sistema est;iloca~izadopordefcctoen;: JAVA-HOMEF\lib\Security\ java. policy (utilice barra oblicuacon Solaris), mientras que el archivo d e politica d e usuario se encuentra p o r defecto e n -USER-HOME% \ j ava. policy. Consulte la docunientaci6n de herran~ienta incluida en su J D K si desea m i s detalles sobre Ins politicas. Es conveniente recordar que a1 iniciar el registro todas las clases y stubs deben estar disponibles e n la ruta d e clase, o Csta n o deberia estar configurado e n absolute, para ajustarse a la c a r p dininiica.

Ejecutar el cliente y el servidor


Para ejecutar el cliente debemos primer0 compilar y ejecutar el archivo Regis terIt. Despuis, necesitamos abrir todavia otra ventana de comandos, de modo que tengamos una ventana ejecutando el rceistro RMI, otra eiecutando el prorrrama Reqister It y la tercera para eiecutar la clase Helloclient especificando nuestro archivo de politica de seguridad:

< ,

,,.:,,

-~~ja~:a..c~~~:~.1city.p1~1i~~j;=~-~:~ H~ z il ~ hl tS + lt i~e ir t~. t~ ~ ~ ~ l i ~ : j ,

El resultado de este sencillo ejcmplo deberia ser el siguiente:

El gestordeseguridad j ava .rmi RMIsecurit yManager amplia la clase j ava . lang . SecurityManages y proporciona el contexto de seguridad en el que ejecutar las aplicaciones RMI. Si n o se ha configurado ningun mecanismo d e seguridad, 10s stubs y las clases s61o p o d r i n ser cargados desde la ruta d e clase local y n o desde el host o desde la clase de c6digo (vCase la secci6n posterior sobre clases cargadas dinaniicamente). Este gestor protege a las aplicaciones de la descarga d e codigo n o seguro via invocaciones de m i t o d o remoto. En J D K 1.3, n o hay realmente necesidad de configurar W I s e c u r i t yManager debido al control de acceso basado e n la politica. Ademis, recuerde que el gestor de seguridad e n JDK 1.3 invoca AccessController .checkPermission (Permission) por defecto y se refiere a un archivo de politica para certificacibn de permiso.

N o hay en realidad ninguna raz6n para establecer el gestor de seguridad R M I S e c u r i t y M a n a g e r si un programa RiMI desempefia un papel puramente de servidor en todos sus vinculos de cornunicaci6n. R M I S e c u r i t y M a n a g e r (y 10s gestores de seguridad definidos por el usuario y obtenidos ampliando R M I S e c u r i t y M a n a g e r ) tiene como objetivo controlar las clases cargadas dindrnicamente por una aplicaci6n cliente para el control de seguridad. Si el cliente tiene acceso a las definiciones de objeto para el host, tampoco hay ninguna raz6n para utilizar R M I S e c u r i t y M a n a g e r en el lado cliente.

Pasar parametros en RMI


L.1

semantics habitual para mktodos en una unica JVM ehti gobernada por dos reglas:
Si el tip0 pasado es una primitiva, el parjlmetro o resultado es pasado por valor. Sin embargo, si el tip0 pasado es u n objeto, el objeto es entonces pasado por referencia.

Cuando un tip0 de datos primitivos es pasado con10 parlmetro a un mitodo, la JVM sirnplemente copia el valor y pasa la copia al mktodo (o la devuelve de iste). Por otro Indo, un objeto reside en el bloque de memorin y una (o rnis) referencias acceden a1 61. Al ser pasado a un mitodo, se realiza una copia de la variable referencia (aurnentando en uno la cuenta de referencia al objeto) y se sitGa en b pila, y la copia va siendo pasada. Dentro del metodo, el c6digo utiliza la copia de la referencia para acceder al objeto. Al invocar cualquier metodo en la referencia, el estado actual del objeto original cambia. Si se altera la referencia en si misma, no se produce ningJn cambio en el objeto original. Sin cmbargo, alterar el objeto al que apunta la referencia si altera el objeto inicialmente creado. Por ello, ique sen~intica se utiliza cuando la invocaci6n de mitodo remoto conlleva pasar parimetros o aceptar un valor de retorno? La respuesta a estn pregunta depende de si 10s parametros son tipos de datos prirnitivos, objetos u objetos remotos. Examinernos estos tipos de parirnetros con detenimiento.

Parametros de primitivas
Cuando un tipo de datos primitivos es pasado con10 parimetro a un mitodo remoto, o bien devuelto desde Cste, el sisterna RMI lo pasa por valor. Una copia del tipo de datos primitivos es enviada al mktodo remoto y el mktodo devuelve una copia de la primitiva desde su JVM. Estos valores son pasados entre cliferentes JVM en un formato e s t h d a r independiente de la rniquina permitiendo a las JVM ejecutadas en diferentes plataformas que se cornuniquen entre ellas de forrna fiable.

Parametros de objeto
Una referencia a un objeto no tiene sentido a travCs de mdtiples JVM puesto que 10s puntos de referencia a un valor en el bloque y diferentes JVM no comparten la memoria crimulo. RMI envia el objeto, no su referencia, entre JVM. Es en realidad el objeto el que es pasado por valor, no la referencia al objeto. De un mod0 similar, una copia del objeto cornpleto es devuelta al programa Ilamador. Un objeto J a w puede ser sencillo o puede referir a otro objeto Java en una estructura cornpleja tip0 grlfico. Puesto que RMI debe enviar al objeto referenciado y a todos 10s objetos a 10s que referencia, utiliza la serialization de objeto RMI, RMI Object Serialization, para transformar el objeto en un formato lineal que puede ser entonces enviado por la red. La serializaci6n de objetos esencialmente extiende un

Procesamiento distribuido con RMI


objeto y cualquier objeto que este referencie. Los objetos serializados pueden ser deserializados en la memoria de la JVM remota y preparados para su uso por un programa Java. Pasar grandes grificos de objetos puede suponer mucho tiempo de C P U y mucho ancho de banda de red. Intente que 10s argumentos de objeto para mktodos remotos y 10s resultados de &tos sean sencillos para mayor optimizaci6n. Los objetos pasados deben implementar la interfaz j a v a . i o . s e r i a l i z a b l e o java.io.Externalizab1e.

Parametros remotos
Pasar objetos remotos como argumentos de metodo o tipos de retorno no es lo mismo que pasar otros objetos. U n programa cliente puede obtener una referencia a un objeto remoto a traves del programa RMI Registry o esta puede ser devuelta a1 cliente desde una llamada metodo (vease el e j e m p ~ o ~ e l l o ~ o en rld la siguiente seccion). Pasar objetos remotos es muy importante, especialmente para retrollamadas. Fijese en el siguiente c6digo:
H e l l o I n t e r f a c e obi M s g I n t e r f a c e rnsg =
=

( H e l l o I n t e r f a z e ) Narnir~g.lookup("/HelloServer"); ob? .getMsg ( ) ;

?Que ocurre cuando M s g I n t e r f a c e es, en si misma, un objeto remoto que ha sido exportado a1 servidor? RMI no devuelve una copia del objeto remoto. Sustituye el objeto remoto por el stub, lo serializa y lo envia a1 cliente. Como apunte, podemos decir que si el cliente envia este objeto remoto de vuelta a1 servidor como otro argumento, el objeto es tratado todavia como un objeto remoto en el servidor y no como local al servidor (aunque lo es). Aunque este pueda parecer un encabezamiento de rendimiento, es crucial para preservar la integridad de la semintica. Considere otro caso: ?quk ocurre cuando el metodo remoto devuelve una referencia a t h i s ?
public class ThisServer e x t e n d s UnicastRernoteObject implements H e l l o I n t e r f a c e [

p u b l i c T h i s S e r v e r ( ) t h r o w s RenioteException[ super ( ) ;

i
public HelloInterface return this; sorneMett1od0 t h r o w s RernoteException

En el c6digo servidor, this hace referencia a la implementaci6n del servidor que reside en la JVM del servidor. Sin embargo, 10s clientes no tienen contact0 direct0 con la otra JVM. Tratan con el proxy del objeto del servidor, el stub. Detras de esto, RMI comprueba 10s parametros de entrada y de salida desde un metodo remoto para ver si implementan la interfaz Remote. Si lo hacen, son claramente reemplazados por el stub correspondiente. Esto provoca en el cliente la ilusi6n de que estin trabajando con 10s objetos locales porque incluso elementos como this pueden ser intercambiados entre diferentes JVM.

Recuerde que 10s archivos de clase en si mismos nunca son serializados, s61o 10s nombres de las clases. Todas las clases deberian poder ser cargadas durante la deserializaci6n utilizando 10s mecanismos habituales de carga de clases.

El recolector de residuos distribuidos


U n o de 10s objetivos de diseiio para las especificaciones de RMI era mantener la perspectiva del cliente de objetos remotos igual que la de otros objetos dentro de su propia JVM. Esto irnplica que 10s objetos rernotos tarnbien deben estar sujetos a la recoleccion de residuos. El sisterna RMI proporciona un algoritmo de recoleccion de residuos distribuidos de contado de referencias basado en Modula-3's Network Objects. Internamente, el servidor mantiene un registro de que clientes han solicitado acceso a1 objeto rernoto. Cuando se realiza una referencia, el servidor marca el objeto como sucio y, cuando todos 10s clientes han suprimido la referencia, el objeto es marcado como limpio. U n objeto limpio es marcado para recoleccion de residuos y reclamado cuando se ejecuta el recolector de residuos. Ademis del mecanismo de cuenta de referencias en el servidor, cuando un cliente obtiene una referencia, tiene en realidad un alquiler del objeto por un tiempo deterrninado. Si el cliente n o renueva la conexion realizando llamadas sucias adicionales al objeto remoto antes de que expire el period0 de alquiler, el recolector de residuos distribuidos asume entonces que el objeto remoto ya no e s t i referenciado por ese cliente (la referencia es considerada como muerta) y el objeto remoto puede ser recolectado como residuo. U n objeto remoto puede implementar la interfaz j a v a . r m i s e r v e r . U n r e f e r e n c e d . ~ s t tiene e un mitodo, u n r e f e r e n c e d ( ) , que es invocado por el periodo de ejecucion RMI cuando ya n o hay clientes que alberguen una referencia viva. Esto permite a1 recolector de residuos distribuidos ( D G C ) cornprobar si alguna referencia remota sigue en uso. El tiempo d e alquiler es controlado por la propiedad de sistema j ava .r m i dgc .leasevalue. (Su valor e s t i e n milisegundos y el valor p o r defect0 es d e 10 minutos.)

Obviamente, toda esta suciedad, limpieza y estos alquileres nunca son visibles para usuarios o clientes. El mecanismo D G C es completamente transparente, se encuentra oculto en la capa de stubs-skeletons y esti abstraido en elpaquete j a v a . r m i .d g c . Es importante recordar que un objeto remoto puede ser recolectado como residuo, quedando indisponible para 10s clientes (lo que tiene con10 resultado habitualmente la exception j a v a . r m i .C o n n e c t E x c e p t i o n ) . Debido a esta sernintica de recolecci6n de residuos, un cliente debe estar preparado para tratar con objetos remotos que hayan "desaparecido". En el servidor, si n o quiere que su objeto "desaparezca", debe siempre retener una referencia explicita de mod0 que n o sea tomada por el recolector de residuos. N o olvide que el registro (en si mismo, un objeto remoto) actua como un cliente para el objeto servidor y, por lo tanto, mantiene un alquiler con el objeto. Por ello, incluso si 10s clientes "reales" se desconectan de un servidor, el metodo u n r e f e r e n c e d ( ) puede n o ser invocado en el objeto servidor mientras que el registro mantiene un alquiler. Considere la siguiente versi6n modificada del mismo ejemplo H e l l o w o r l d que dernuestra c6mo funciona la recolecci6n de residuos y d m 0 puede ser utilizado el metodo u n r e f e r e n c e d ( ) .Ya hemos estudiado c6mo puede un cliente obtener una referencia a un objeto remoto como resultado de una invocaci6n de metodo con anterioridad en la secci6n sobre pasado de parimetros. Este ejemplo utiliza este concepto. Modificamos la interfaz para devolver un objeto remoto en lugar de una cadena (string):
import

j a v a . rrni. *;

Procesamiento distribuido con RMI

p u b l i c i n t e r f a c e H e l 1 , j I n t e r f a c e e x t e r ~ d s j a v a . r m i . Remate [ p u b l i c MsgInter-f a c e getMsg ( ) throws RemoteExceptian, E x c e p t i o n ;


1

La implementacidn del objeto remoto de esta interfaz es tambien bastante sencilla:


i r n ~ ~ import import impart public ~ ja ~v r a. t j ava. java. j ava. class i o . i; rml. *; rrni.~erver.~; u t i l . Date; Helloserver ehtends IJnicastRemoteObject implements H e l l o I n t e r f a c e {
{

public HelloServer ( ) super();

t l i r ~ ~ wR s ernoteException

p u b l i c M s q I r t t e r f a c e qetMsq ( ) t h r o w s RemoteEsception, r e t u r n ( M s g I n t e r f a c e ) new M s g S e r v e r ( ) ;

Exception

M s g I n t e r f a z n o tiene metodos y s610 se utiliza para marcar el objeto que es pasado como remoto:
import import public java.io.Seriali:able; java.rmi.server.*; interface MsqInterface extends j a v a . rmi .Remote
[

La sencilla implementacidn de esta interfaz e s t i disefiada para interceptar 10s eventos del objeto imprimiendo informaci6n cuando el objeto es creado, cuando ya no es referenciado, cuando se finaliza y despues se elimina. Este objeto tambien implements la interfaz Unreferenced y el metodo u n r e f e r e n c e d ( ) . El m e t o d o u n r e f e r e n c e d ( ) seri invocado cuando no haya referencias de cliente al objeto; se invoca f i n a l i z e ( ) justo antes de que el objeto sea recolectado como residuo:
import import import public java.io.Serialirab1e; java.rmi.server.+; j ava .r m i . * ; class MsqServer e x t e n d s UnicastRemoteObject implemerits M s g l n t e r f a c e , S e r i a l i z a b l e , el nhmero 3e instancias

Unreferenced

/ / E s t a b l e c e r un / / de esta clase
private static

contador para counter; para la

creadas

int

/ / C o n t e r ~ e r un i d private i n t id;

instancia

del

imbjeto

p u b l l c MsgServer ( ) ttjr,>ws RernoteException { super ( ) ; S y s t e m . o u t . p r i n t l n [ " C r e a t e d Msg:" + c o u n t e r ) ; c,>unter++; s e t I d ( counter);


I

public void f i n a l i z e 0 super. f i r t a l i r e ( ) ;

throws

Throwable

Syster~~.aut,printlr~("Finalizer called

f o r Msg:

"

id);

Capitulo 3
publlc void unreferenced(){ Systern.out. p r i n t l n ("The unreferenced ( )method c a l l e d

for que

Msg:

" + i d );
r~adie

// //
I

s i e s n e c e s a r i o , i n v o c a m o s a q u i u r ~ e x p o r t o b j e c t ya que e s t e u t i l i z a n d o u n e x p o r t o b j e c t ( e s t e , c l a r o ) ;

r ~ ohay

p r i v a t e void s e t I d ( i n t i d ) { this.id=id;

I
El programa de registro sigue siendo el mismo de 10s ejemplos anteriores:
irnpsrt j a v a . rrni

.-;

p u b l i c s t a t i c voicj, r n a i r l i s t r i r ~ g a r g s [ ] ) { try i Hellc~Ssr..ler o b j = r~ew HellL'Server ( ) ; Naming. r e b i r d ( " / H e l l o S e r v t r " , o b j ) ; System.out . p r l r ~ t l( r" ~H e l l ~ . ~ S e r v e b r qund I cat(:h ( E x c e p t l , : ~ r e ~) { Sy~ttm.out.printlr~(ej;

in

r s t j i : : t i y U );

Modificamos el cliente ligeramente para crear multiples instancias del objeto r e m o t o M s g S e r v e r ( ) en el servidor (instanciamos explicitamente un objeto en el metodo g e t M s g ( ) ). Necesitamos realizar esta operacion para nuestra demostraci6n porque la JVM ejecuta el recolector de residuos distribuidos (igual que el habitual recolector de residuos), solo cuando "cree" que es necesario reclamar memoria:
import public j a v a . rrni class

.+ ;
{

HellcClient

p u b l i c s t a t i c v o i d r n a i r ~ ( S t r i n ga r g s [ 1 ) { i f ( S y s t e m . g e t S e c ~ i r i t y M a r ~ a g (e )r == r t 1 ~ 1 1 ){ System. s e t S e c u r i t y M a n a g e r (new RMISecurityManager ( ) ) ;

I
try

i
HelloInterfact obj = (Hellolnterface) Narnir~g.l~~okup("/HelloSer~v'er"); f o r ( i n t i = 0; i < 1 0 0 ; i + + ){ M s g I n t e r f a c e rnsg = o b j . g e t M s g ( ) ;

1 catch (Ezception e )

Systeni.out.prir~tlr~("HelloClier~t exception:

"

e);

I I
I

Inicie el sewidor despues de compilar las clases y de generar 10s stubs (y 10s skeletons si es necesario) para H e l l o S e r v e r y p a r a M s g S e r v e r con 10s siguientes elementos (cambiando la ruta c o d e b a s e cuando proceda; consulte la pr6xima secci6n para mis detalles sobre c o d e b a s e ) :
javac +. java rrnic - v 1 . 2 H e l l o S e r v e r rrnic - v 1 . 2 MsqServer

Procesamiento distribuido con RMI

Una vez mis, puede que desee experinientar con la propiedad del valor de alquiler asi corno con las opciones -ms ); -nix para configurar el bloque de memoria para este ejemplo. Aqui tiene un fragment0 de

LeaseCheckIntervtd en s u n . r m l . t r a n s p o r t . DGcImpl es leido desde la propiedad s u n . r m i . d g c , c h e c k I n t e r v a 1 sin tener en cuentn el valoractualde la variable l e a s e v a l u e . Esto provoca un retraso de cinco minutos a1 eliminar objetos no utilrzados, incluso si l e a s e v a l u e se fija en u n valor menor. Para e v i u r este problems, fije la propiedad s u n . r m i . d g c . c h e c k I n t e r v a 1 en la mitad de la configuraci6n de
lava. rmi.dgc. leasevalue.

Clases de carga dinarnica


Hemos hablado anteriormente sobre c6mo las referencias, 10s stubs, 10s parimetros y las factorias de sockets son enviadas al cliente y sobre c6mo las definiciones de clase no lo son. El cargado de clase dinimico hace referencia a este filtimo, haciendo que las definiciones e s t h disponibles. El cargado dinimico de clase lleva en Java bastante tiempo y esta capacidad para cargar e instanciar dinirnicarnente clases es un concept0 muy eficaz. Los applet, por eiernplo, son descargados a1 navegador del cliente desde un servidor webeyson ejecutados en l a j ~ ~ ~clienie. d e l Esto proporciona al perio-do de ejecuci6n del cliente la capacidad para acceder a aplicaciones que nunca han sido instaladas en su sisterna. Se da por sentado que el lector esti familiarizado con el funcionarniento de 10s applet y c6rno utilizan la propiedad codebase. Resumiendo, c o d e b a s e es el lugar desde el que el cargador de clase carga clases en la JVM. Esto significa que las clases pueden ser desplegadas en un lugar central, corno un servidor Web, para un sistema distribuido y todas las aplicaciones del sistema pueden descargar 10s archivos de clase para operar. Hay dos importantes propiedades de sisterna en RMI:

Capitulo 3
0

Java.rmi.server.codebase

Esta especifica el URL (una localizaci6n file : / /, ftp : / / o ht t p : / / ) desde donde se puede acceder a las clases. Si un objeto es pasado c'omo argument0 de metodo o tip0 de retorno, la JVM cliente necesita cargar 10s archivos de clase para ese objeto. Cuando RMI serializa el objeto, inserta el URL especificado por esta propiedad junto a1 objeto.
0

Java.rmi.server.useCodebaseOn1y

Esta propiedad es utilizada para notificar a1 cliente que debe cargar clases unicamente desde la posici6n de base de codigo, codebase. Repasemos el proceso de exportaci6n y registro de un objeto remoto y observ6moslo a trav6s de una lupa:
0 A1 instanciar el objeto remoto y registrarlo con el registro (nuestro programa Regis terI t de 10s ejemplos anteriores), la base de c6digo es especificada por la propiedad j ava .rmi .server. codebas e.

Cuando se realiza la llamada bind 0 , el registro utiliza esta base de codigo para ubicar el stub para el objeto. Recuerde que el registro mismo es un cliente para el objeto. Una vez se ha conseguido esto con exito, el registro asocia el objeto a un nombre y la base de c6digo es guardada junto con la referencia a1 objeto remoto en el registro.
O Cuando un cliente solicita una referencia a1 objeto remoto, el registro devuelve el stub al

cliente. El cliente busca la definicidn de clase del stub en su ruta de clase local (siempre se busca antes la ruta de clae que la base de cbdigo) y entonces carga la clase local. Si la definici6n de clase de stub n o se encuentra en la ruta de clase, el cliente intentari recuperar la definici6n de clase de la base de c6digo del objeto remoto que ha sido almacenado en el registro.
0 La definition de clase para el stub y cualquier otra clase que necesite, como factorias de Sockets,

son descargadas a1 cliente JVM desde la base de codigo http o ftp.


0

Cuando todas las definiciones de clase estin disponibles, el mitodo proxy del stub llama el objeto en el servidor.

Utilizando las dos propiedades y el rnecanismo de descarga, pueden establecerse cinco configuraciones potenciales para distribuir clases:
0 Cerrada

N o hay carga dinimica y todas las clases estin ubicadas en las JVM respectivas y son cargadas desde la ruta de clase local ( java . rmi . server. codebase no configurado).
0

Dinhrnica lado cliente En el cliente, algunas clases son cargadas desde la ruta de clase local y otras desde la base de c6digo especificado por el servidor. Es similar a la configuraci6n dinimica lado cliente. Algunas clases en el servidor son cargadas localmente y otras desde la base de c6digo especificado por el cliente (por ejemplo, en el caso de retrollamadas desde el servidor a1 cliente).

0 Dinhrnica lado servidor

Cliente de autoarranque Todo el c6digo de cliente es cargado desde el codebase mediante un pequefio programa en el cliente (cargador de autoarranque). Servidor de autoarranque Igual que el anterior, s61o que en el lado servidor. El servidor utiliza un pequefio programa (cargador de autoarranque).

Procesamiento distribuido con RMI


Hay dos clases, j a v a . r m i .R M I S e c u r i t y M a n a g e r y j a v a . r m i .RMIClassLoader,quecomprueban el context0 de seguridad. El sistema RMI s61o descargari clases de ubicaciones remotas si ha sido enviado un gestor de seguridad. El R M I C l a s s L o a d e r tiene un mttodo importante:
public static Class loadClass(String codebase, String name)

Este mttodo carga la clase desde la base de c6digo especificada. Otras formas de sobrecarga de este mttodo toman un URL para una base de c6diog o una lista de cademas de m~iltiples URL. Tomemos el ejemplo HelloWorld y configurtmoslo en la configuraci6n cliente de arranque y sewidor de arranque. Esta configuraci6n es habitualmente la mis popular debido a su flexibilidad. Descargaremos:
0 Todas las clases del cliente, incluida la clase cliente, al cliente desde el sewidor Web.
0 Todas las clases del sewidor, incluida la clase sewidor, desde un sewidor Web central.

S61o necesitaremos una sends clase de arranque para el cliente y una para el sewidor. Primero, vamos a retocar un poco la clase H e l l o W o r l d de modo que se conecte a] sewidor a1 ser instanciada:
import java.rmi.'; public class Helloilient
{

public Helloclient [ ) ( try ( HelloInterface obj = [HelloInterface) Naming.lookup( "rmi://localhost/HelloServer"); String message = obj . sayHello ( ) ; System.out .prir,tln( m e s s a g e ) ; ! catch [Exception e ) 1 System.out .println ("HelloClient excepciton: * 1

+ e) ;

Ya esti. Mantenemos la implementaci6n remota ( H e l l o s e r v e r . j a v a ) y la interfaz ( H e l l o I n t e r f a c e . ja v a ) igual queennuestro ejemplo initial. Escribamos ahora una clase de arraque, bootstrapped, (en lugar del archivo R e g i s t e r ~t que utilizamos anteriormente) que inicie el sewidor. Accede a la propiedad c o d e b a s e y carga la clase de sewidor desde la base de c6digo u t i l i z a n d o ~ ~ ~ ~ l a s s r: ~oade
import import import import import java. rmi .Naming; j ava. rmi. Remote; j ava. rmi. RMISecurityManager; java.rmi.server.RMIC1assLoader; java.util.Properties;

public class Dynamicserver { public static void mairt[String args[])


{

/ / Crear e instalar un gestor de seguridad if (System.getSecurityManager() == null) { Systern.setSecurityManager(new RMISecurityManager());

Capitulo 3
Praperties p = System.getProperties ( ) ; String url = p.getPrsperty ( " j ava. rmi .server.codebase") ; Class serverclass = RMIClassLoader.loadClass(url, "HelloServer"); ( ) ) ; Naming. rebind ( " / H e l l a S e r v e r " , ( R e m o t e ) s e r v e r c l a s s .r~ewIr~star~ce System.out.println("He11oServer bound ~n registry"); catch (Exception e) [ System.out . p r i n t l n ( e ) ;

I
I

Cuando la clase descargada es instanciada con n e w I n s t a n c e ( ) , el constructor para la clase es invocado (nuestro constructor H e l l o S e r v e r ( ) ) y el objeto es exportado en el constructor y registrado con el registro. Los cinco pasos que ya hemos descrito en este capitulo (Desarrollo de aplicaciones con RMI), suceden conjuntamente entre el servidor y el registro. Existe un programa de arranque similar para el cliente que accede a la propiedad codebase y carga la clase cliente. Cuando la clase cliente descargada es instanciada, conecta a1 servidor y busca el objeto. Una vez mis, 10s pasos de 1 a 5 suceden entre el cliente y el registro:
import import import public
j a v a . rmi. RMISecurityMar~ager; j a v a . rnii .server.RMIClassLoader; java.uti1.Properties; class DynamicClier~t
J ,

p ~ ~ b l i DynamicClient() c throws Exceptisn [ Properties p = System.getProperties[); String url = p.getProperty ("java.rmi.server. codebase") ; Class clientClass = RMIClassLoader. loadClass ( u r l , "He1 1oClient") ;
/ / Start the client clientclass. newInstar~ce ( )
;

I
public static void main (String args[]) [ System. setSecurityManager ( n e w RMISecurityManaqer try i D y n a m i ~ C l i e n t d c = n e w Dyr~amicClier~t ( ) ; 1 catch (Exception e) { Systern.out.println ( e ) ;
( ) ) ;

Compile todas las clases y genere 10s stubs. Ahora necesitamos situar 10s archivos de clase H e l l o W o r l d en un servidor Web de modo que D y n a m i c s e r v e r pueda descargarlos en el periodo de ejecucidn. Para este ejemplo, utilizaremos un pequefio servidor HTTP de prueba de Sun llamado C l a s s F i l e S e r v e r (tambikn incluido en el c6digo fuente). Sitfie 10s cuatro archivos de clase para el ejemplo H e l l o W o r l d en un directorio ( \ p u b l i c h t m l ) en el servidor HTTP. Primero, inicie el registro RMI utilizando:
r m i r e g i s t r y -J-Djava.security.p'i1icy=1egisterit.po1icy

despu& inicie el servidor HTTP. Para ClassFileServer seria algo asi (asumiendo que ClassFileServer se encuentra en el classpath):
java ClassFileServer
8060 %BOOK. HOME%\ChO3\Dynamic\webserver\pub1ic_html

Procesamiento distribuido con RMI


El primer parirnetro de esta linea de comnndo especifica el puerto en el que se ejecuta el servidor y el segundo pnrimetro es la fuente . para que . lob archivos sean servidos. Probablernente, resultari un poco m i s ripido configurar un archivo por lotes para ejecutar estos comandos.

Entonceb, ejecutanios D y n a m i c s e r v e r especificando c o d e b a s e c o m o servidor Web:

Finalmente, e j e c u t e D y n a m i c C l i e n t , proporcionando de nuevo c l c o d e b a s e :

2 C u a n d o inicianios el DynamicServer, Cste accede a la base de c6digo descarga la clabe de implenientaci6n y esporta el objeto
U El registro utiliza el c6digo de base para descargar el btub y asociar el objeto, registrando la basc de

c6digo de utilizada
d

C u a n d o inicia el D y n a m i c c l i e n t , contacta de nuevo con la base de c6digoy descarga la clase de cliente y el stub, e invoca un metodo en el objeto servidor

Resumiendo los pasos para ejecutar el ejeniplo: Nota: In fuente descargable contiene archivo por lotes de prueba para ejecutar el c6digo.
LI I n i c i e r m i r e g i s t r y :

i Inicie cl servidor de archivo de clase. Aseglirese de que las clases cornpiladas del primer ejeniplo H e l l o W o r l d asi conlo 10s stubs, e s t i n disponibles en la carpeta public-html :

Obberve que t o d o s los archivos de cliente HelloWorld, de servidor y s t u b se ubican en un s o l o lugar. La linica distribuci6n para el servidor es una clase y el linico archivo n e c e s ~ r i o para la distribucibn d e cliente es una clase:

Capitulo 3

Hernos visto anteriorrnente corno un cliente puede obtener una referencia a un objeto remoto corno resultado de una invocacion de rnktodo. De hecho, en realidad vimos en el ejemplo de D G C corn0 un objeto rernoto puede ser pasado dinimicarnente. Recuerde que habiarnos destacado inicialrnente que cliente y sewidor son tkrminos utilizados para describir un rol, no ubicaciones fisicas o arquitecturas. U n cliente tambikn puede ser un objeto remoto. En rnuchas situaciones, un sewidor puede necesitar realizar una llarnada rernota a un cliente, por ejernplo, datos de progreso o notificaciones administrativas. U n buen ejemplo seria una aplicaci6n chat donde todos 10s clientes son objetos remotos.

1 . El objeto 2 lnvoca un rnetodo rernoto en el objeto 1 y se pasa a si mlsrno corno un


pararnetro para ese rnetodo

2. El objeto 2 ut~l~za la referenc~a que ha obtenldo corno resultado (1) e lnvoca un rnetodo en esa referenc~a
I

N o hay nada de particular en la comunicaci6n entre pares o en las retrollarnadas entre objetos rernotos. Todo lo que ocurre es que una referencia rernota es pasada y que 10s rnktodos son invocados en esa referencia. Tomemos en mismo ejernplo H e l l o w o r l d que examinamos en un principio y modifiquernoslo para dernostrar las retrollamadas. La interfaz r e m o t a , H e l l o I n t e r f a c e , tiene un metodo que toma u n c l i e n t I n t e r f a c e corno argumento:
public interface HelloInterface extends java.rmi.Remote { String sayHello(Client1nterface app) throws java.rmi.RemoteException;

I
Para el cliente, la ClientInterface es tambien muy sencilla, con un solo metodo:
public interface ClientInterface extends java.rmi.Rernote { void popup(String n s g ) throws java.rmi.RemoteException;

1 ~ e l l o ~ e r vi e mrP ~ e m e n t a ~ e l 1 o 1 n t e r f ae cinvocael e metodopopup ( ) e n c l i e n t I n t e r f a c e corno se muestra a continuaci6n:


import import import import java.io.*; j ava. rrni . * ; j ava. rmi. server.*; java.uti1. Date;

Procesamiento distri buido con RMI


public class Helloserver extends 1JrlicastRernoteObject implements HelloIr,terface {
( )

public Helloserver super ( ) ;

throws RemoteExceptlon

1
public String s a y H e l l o ( C l i e r ~ t I r ~ t e r f a c c e a ) throws RemoteExceptinr~ { ca.popup("This is a message from the server!"); return "Hello World, the current system time is " + new D a t e ( ) ;

I
El cliente que invoca mitodos en el servidor necesita ser un objeto remoto en si mismo. Escribamos un sencillo applet para demostrar esto. El applet se exporta a si mismo y empieza a escuchar llamadas de entrada invocando explicitamente el m i t o d o ~ n i c a s t ~ e m o t j ee ~cbt .e x p o r t O b j e c t ( t h i s ) (una forma sobrecargada de este m i t o d o le permite especificar tambiin el puerto):
impart impart impart import import public java.applet.*; lava. awt . * ; j ava. io. Serializable; j ava. rmi. * ; j ava. rrni. s e r v e r . * ; class CallbackApplet extends Applet implements ClientIr~terface, Serializable {

Strir,g message = " - n / a - " ; Frame f =new Frame(); Label 11= rlew Label i " public void ir~it ( 1 1 f.add(l1); try i / / Exportar el objeto U n i c a s t R e r n o t e O b j e ~ t ~ e s p o r t O b j e c t( t h i s ) ; Strir,g host = "rrni://" + getCodeBase().getHost()+ "/HellaServer"; HelloIr,terface nbj = (HelloInterface )Naming.lookup ( h o s t ); message = obj . s a y H e l l o ( ( C l i e n t I n t e r f a c e ) t h i s ); 1 catch (Exception e ) { Systern.out .println ("HelloApplet exceptian: " t e ) ;

I
I

/ / Mostrar el rnerisaje en la applet public void paint(Graphics g ) { g.drawString(rnessage, 25, 5 0 );

I
/ / Implementar la interfaz public void popup(Strir1g t x t ) throws RemoteException{ ll.setText(txt); f.setSize(100,lOO); f.show0;

I
I
Cuando el applet es cargado, localiza el objeto servidor e invoca el mitodo remoto. Se pasa a si mismo como argument0 para ese mitodo. C o m o resultado, el stub es transportado a1 servidor y el servidor puede ahora invertir 10s roles. A c t ~ como a un cliente para este applet y puede invocar el m i t o d o POPUP ( ) .

Capitulo 3
Necesitamos una simple pigina H T M L para este applet ( A p p l e t .h t m l ) :

Es tan sencillo c o m o esto. Generamos 10s stubs para el cliente y el servidor ejecutando r m i c en er utilizando la C a l l b a c k A p p l e t y H e l l o s e r v e r . Inicie el registro y r e g i s t r e ~ e l l o ~ e r v con61 misma clase R e g i s t e r 1 t que hemos utilizado anteriormente. El applet debe ser cargado desde u n servidor W e b en el host (recuerde que 10s applet sin firmar pueden conectar de nuevo con el servidor) y puede utilizar su propio servidor W e b o el de prueba C l a s s F i l e S e r v e r utilizado en el ejemplo anterior. Todas las clases que el cliente necesita deben estar accesibles en el servidor Web. Las definiciones de archivo de clase stub de ~ a l l b a c k ~ ~ deberian ~ l e t estar disponibles en la ruta de clase de objetos del servidor o deberian ser cargadas dinimicamente como hemos visto anteriormente. Tamhien puede probar las aplicaciones utilizando AppletViewer. Configure las preferencias e n A p p l e t Viewer como"unrestricted". Escriba u n archivo H T M L con el siguiente codigo ( ~ p p l e t v i e w e . rh t m l ) :
cht rnl> capplet (:debase=". " </applet,> / t, t 11, i ?
~:~:~de="Callbacl.:Appl ce l ta. s c "

width=300

heigt,t=266>

Ejecute el ejemplo despuks de iniciar el registro y el servidor desde el mismo directorio como el archivo H T M L y 10s archivos de clase.
applttviewer -J-Pjava.

security.poiicy=reglsttrit . p o l i c y A p ~ , l e t V i e w e r h . tml

Finalmente, a1 ejecutar este ejemplo, obtenemos algo parecido a esto:

Applet

Hello World, the current system time is Fn Aug 1 7 1 g:57:ll BST 2001

This is a message from the sewer!

Procesamiento distribuido con RMI

Activacion de objeto
Los objetos remotos que hemos analizado hasta el momento son instancias de la clase j a v a . r m i .U n i c a s t R e m o t e O b j e c t y tienen una caracteristica principal. Son accesibles en todo momento, incluso cuando no hay clientes ejecutando. Consideremos un marco hipotktico en el que el numero de objetos remotos, o de recursos utilizados por ellos en un servidor sea alto. Esta situaci6n fue identificada como un importante cue110 de botella en Java 2 , por lo que se introdujo el concept0 de activaci6n. La activacion de objetos permite ejecutar objetos remotos dependiendo de la necesidad. Es decir, cuando se accede a u n objeto remoto "activable" (via invocacion de metodo), si ese objeto remoto n o estd siendo ejecutado en ese momento, el sistema inicia la ejecuci6n del objeto e n una JVM apropiada. RMI utiliza la activaci6n lenta: es aquella en la que la activaci6n de u n objeto es aplazada hasta el primer uso de u n cliente, la primera invocaci6n de mitodo. Entonces, icuil es la diferencia entre un objeto activable y el habitual objeto remoto desde la perspectiva de un cliente? Ninguna. Para el cliente, todo el mecanismo de activacion es transparente y el cliente nunca es consciente de lo que esti ocurriendo detris de la escena. Las referencias a1 objeto remoto pueden ser consideradas referencias lentas o imperfectas. Las referencias a objetos activables contienen informacion persistente de descripci6n que permite la activation del subsistema para saber que el objeto deberia estar iniciado si no esti ya siendo ejecutado. Despuks de que una referencia activable sea utilizada por primera vez, la capa de referencia remota cambia a referencia remota regular de mod0 que no tenga que pasar por el sistema de activaci6n posteriormente. Puesto que el sistema de activaci6n puede cambiar la referencia lenta a referencia remota activa, las referencias a objetos activables estin siempre disponibles. Sin embargo, las referencias a un objeto remoto no sobreviven despuks de un fallo del sistema o de reiniciar. Para comprender la verdadera semintica de utilizar el modelo de activacibn, debemos familiarizarnos con algunos tkrminos utiles:

O Activador El activador es un componente principal en el sewidor. Facilita la activaci6n del objeto remoto registrando toda la informacidn necesaria para activar un objeto y es responsable de iniciar instancias de las JVM en el sewidor si es necesario.
0

G r u p o de activaci6n U n grupo de activacion crea instancias de objetos en su grupo e informa a su monitor sobre 10s diferentes estados activos y pasivos. La analogia mas cercana a un grupo de activation es un grupo thread (hebra). U n grupo de activaci6n es en esencia una instancia cornpleta, independiente de la JVM que existe unicamente para albergar grupos de objetos activados. Esta nueva JVM es iniciada por el activador cuando asi se requiere. Pueden existir multiples grupos de activaci6n.

O Monitor de activaci6n Cada grupo de activaci6n tiene un monitor de activaci6n que registra el estado de un objeto en el grupo y el estado del grupo en su conjunto. El monitor de activaci6n es creado cuando se activa el grupo. O Sistema de activaci6n El sistema de activaci6n proporciona un medio para registrar grupos y objetos activables para ser activados dentro de esos grupos. Trabaja en estrecha relaci6n con el activador, que activa objetos

Capitulo 3
registrados mediante el sistema de activaci6n y con el monitor de activacibn, y obtiene informacidn sobre objetos activos e inactivos, y grupos inactivos. El modelo de activaci6n y sus implementaciones asociadas aparece resumido en la siguiente tabla:

Entidad Activador

Implementaci6n java. rmi. activation-Activator

Implementado como Interfaz (observe que el activador es en si mismo un objeto remoto). Claseabstracta. Interfaz. Interfaz.

Grupode activaci6n Monitor de activaci6n Sistemade activaci6n

java.rmi.activation.ActivationGroup

j a v a . r m i . activation.ActivationMonitor
java.rmi.activation.ActivationSystem

El mecanismo de activacion utiliza identificadores y descriptores. Aunque pueda parecer excesivo, merece la pena recordar estos puntos:

0 Cada objeto activable tiene un I D y un descriptor.

Cada objeto activable pertenece a un grupo de activacion. El grupo mismo tiene un I D y un descriptor.

El grupo de activacion
U n grupo de activaci61-1,como ya hemos dicho anteriormente, se utiliza para mantener un grupo de objetos activables. El grupo de activaci6n esti asociado a un identificador de grupo ( j a v a . r m i . A c t i v a t i o n . ~ c t i v a t i o n ~ r o uypa ~ n ~d)e s c r i ~ t o r d e g r u p o ( j a v a . r m i .a c t i v a t i o n . A c t i v a t i o n ~ r o u p D e s c queidentifican ) y describenelgrupodeactivaci6n respectivamente. U n grupo de activaci6n es creado explicitamente como resultado de invocar el mktodo ActivationGroup.createGroup():
public static ActivationGroup createGroup(ActivationGroup1D id, ActivationGroupDesc desc, long incarnation)

donde:

0 i d e s el identificador del grupo de activacih


0

d e s c es el descriptor del grupo de activaci6n

0 i n c a r n a t i o n es el n ~ m e r o de personification del grupo de activaci6n (cero en la creaci6n inicial de un grupo)


A c t i v a t i o n G r o u p I ~ademis , de identificar el grupo de forma exclusiva dentro del sistema de activacion, tambikn contiene una referencia al sistema de activacion del grupo. Esto permite al grupo interactuar con el sistema siempre y cada vez que sea necesario. Todos 10s objetos con el mismo A c t i v a t i o n G r o u p I D son activados en la misma JVM.

Procesamiento distri buido con RMI


U n A c t i v a t i o n G r o u p D e s c contiene la informacidn necesaria para crear o recrear el grupo en el que activar objetos. Contiene:
O

E l n o m b r e d e ~ l a s e d e l g r u ~Recuerdeque o. j a v a . r m i .a c t i v a t i o n . A c t i v a t i o n G r o u p e s una clase abstracts y el activador ( r m i d ) proporciona internamente su implementacidn concreta (par ejemplo, la clasesun. r m i . s e r v e r . A c t i v a t i o n G r o u p I m p l ) .

0 La ubicacibn de la clase del grupo.


O

U n objeto escrito y transmitido (marshaled) que puede contener datos de inicializaci6n especificos del grupo.

que especifica las opciones A c t i v a t i o n G r o u p D e s c contiene una clase interna~ommand~nvironment de entorno de arranque para las clases de implementaci6n de A c t i v a t i o n G r o u p . Esto permite un control exacto sobre las opciones de comando utilizadas para iniciar la JVM descendiente (un C o m m a n d E n v i r o n m e n t nulo hace referencia a 10s valores por defecto de r m i d ) . A c t i v a t i o n G r o u p D e s c puede ser creado utilizando uno de 10s dos constructores especificados a continuaci6n:
O

Construir un descriptor de grupo que utilice la omisi6n del sistema para la implementaci6n de grupo y la localization de c6digo:

ActivationGroupDesc(Properties overrides, ActivationGroupDesc,CommandEnvironment cmd)

O Especificar una implementaci6n de grupo y un entorno de ejecuci6n alternativo para set utilizado
por el grupo:
ActivationGroupDesc(String className, String location, Marshalledobject data, Properties overrides, ActivationGroupDesc.CommandEnvironment cmd)

Hemos dado un ripido repaso a 10s grupos de activacidn. Veamos ahora algo de cddigo que resume la creacidn de grupos de activacibn:
/ / Crear el descriptor d e grupo Properties env = new Properties ( 1 ; env.put ("java.security.po1icyYY,"fi1e://%BOOKHOME%/Ch03/Activatable/ registerit .policy") ; ActivationGroupDesc mygroupdes = n e w ActivationGroupDesc(props, n u l l ) ;

/ / Obtener una referencia a1 sistema d e activaci6n ActivationSystem mysystem= ActivationGroup.getSystem();

/ / Registrar el descriptor de grupo con el sistema de activaci6n y obtener el id del grupo id ActivationGroupID groupid=y system.registerGroup(mygroupdes);
/ / Ahora que tenemos el id y el descriptor podemos crear el grupo explicitamente Activatior~Group.createGroup(groupid, mygroupdes, 0);

Igual que A c t i v a t i o n G r o u p I D es un I D para el g r u p o , A c t i v a t i o n I D es un I D para el objeto. Una vez que el objeto es registrado con el sistema de activacidn, se le asigna un A c t i v a t i o n I D . Contiene dos elementos esenciales de informacibn:

o Una referencia remota a1 activador del obieto

Procesamiento distribuido con RMI


O

Invocando el mktodo e s t i t i c o ~ c t i v a t a b l . er e g i s t e r ( A c t i v a t i o n D e s c d e s c )

o Instanciando el objeto mismo utilizando el primer o el segundo constructor de la clase


A c t i v a t a b l e (que toma A c t i v a t i o n I D como parimetro). Este registra y exporta el objeto.
O

Exportando el objeto explicitamente mediante el primer o el segundo mitodo e x p o r t o b j e c t de l a c l a s e A c t i v a t a b l e que toma u n A c t i v a t i o n I D , la implementaci6n de un objeto remoto y un numero de puerto como argumentos. Este registra y exporta el objeto.

()

Detris de las escenas esti ocurriendo lo siguiente:

o Cuando se genera un stub para un objeto activable, contiene information especial sobre el objeto.
Esta informaci6n incluye el identificador de activaci6n e informaci6n sobre el tipo de referencia remota del objeto.
0 El activador localiza el descriptor de activaci6n del objeto y el grupo de activaci6n. Si el grupo de

activacion en el que deberia estar este objeto n o existe, el activador inicia una instancia de una JVM, crea un grupo de activacion y despuks envia la solicitud de activaci6n a ese grupo. El grupo de activaci6n carga la clase para el objeto y lo instancia (utilizando constructores especiales que toman varios argumentos, como veremos pronto). Cuando el objeto es activado, el grupo de activaci6n devuelve una referencia de objeto a1 activador (ksta es una referencia serializada o marshaled). El activador graba el identificador de activaci6n y el pareado de referencia y devuelve la referencia viva a1 stub. El stub envia entonces invocaciones de metodo mediante esta referencia viva directamente a1 objeto remoto (la referencia viva es como cualquier otra referencia). Resumamos todo lo que hemos visto hasta ahora volviendo a ejecutar el ejemplo H e l l o w o r l d para convertirlo en activable.

Convertir objetos en activables


C o m o hemos visto, existen algunas entidades cooperantes en el marco de trabajo de la activacion que hacen todo sea posible:

o El objeto.
O

El programa envoltorio que registra el objeto. Es similar al programa RegisterIt que utilizamos anteriormente. Normalmente realiza unas llamadas de metodo a1 sistema de activaci6n para proporcionar detalles sobre c6mo deberia ser activado el objeto. La tercera entidad es el demonio (daemon) de activacidn que graba informacibn, igual que el registro, sobre cuindo y quk hacer con 10s objetos (este daemon es r m i d ) .

Teniendo en cuenta estas entidades, 10s pasos para convertir un objeto en activable pueden resumirse del siguiente modo:
O

Elobjeto debeampliarlaclase j a v a . r m i . A c t i v a t i o n . A c t i v a t a b l e enlugardelaclase U n i c a s t R e m o t e O b j e c t (existe una alternativa a esto que examinaremos posteriormente). activaci6n de t i p o ~ c t i v a t i o ny~sus ~ , datos de activaci6n opcionales, un j a v a r m i .M a r s h a l l e d O b j e c t . Este es distinto de 10s objetos remotos no activables, que incluyen un constructor sin argumento. Este constructor especial es llamado por el sistema RMI cuando activa el objeto.

0 El objeto debe incluir un constructor especial que tome dos argumentos, su identificador de

Capitulo 3
0 U n descriptor de activation (java . rmi .Activation.Activation~esc) debe ser creado y

registrado con el activador (rimd). Es importante destacar que la interfaz remota del objeto n o necesita ser cambiada o modificada en n i n g h caso. Es logic0 porque solo estamos cambiando la implementation de la instancia del objeto, n o la perception exterior del objeto.

Paso 1 :Crear la interfaz remota


N o se diferencia de lo que teniamos anteriormente:
lrnprt j ava

.r m i .

Paso 2: Crear la implernentacion del objeto


Esta clase arnplia j ava. rmi .Activation .Activatable eimplementa la interfazremota (puesto que la clase Activatable amplia RemoteObj ect). Ademis, debe contener un constructor de dos argumentos que tomaActivationID yMarshaledObj ect como argumentos. Este constructor debe llamar a 10s constructores de superclase adecuados para asegurar la inicializacion:
i m F > o r t j a v a . 1 - n i l . '; irnp(,rt j a v a . rnii. a c t i v a t i o n . * ; import j a v a . u t i 1 .Date; public class HelloServele s t e r ~ d sActivatable implenier~ts H e l l o I n t e r f a c e
{

publiz

H e l l o S e r v e r ( A c t i T ~ a t i o r ~ IiD d , Marshaledobject d a t a ) throws RemoteExceptior~ { / / R e q i s t r a e l o b j e t o c o n una a s t i T J a c i 6 n d e l s i s t e m a / / R e g i s t r a r l c ~ 7 e s p o r t a r l o en u r ~ p u e r t o a r ~ i r ~ i m o superiid, 0 ) ;

p ~ b l i i : S t r i n g s a y H e l l o ( ) thrt-.:h..- R e m o t e E x c e ~ ' t i i , n l l . e t ! l r r ~" H r l l ' - ~ W o r l d , t h e ' : u r r e n t system time i s

"

+ ~r.eh, D a t e ( ) ;

Paso 3: Registrar el objeto con el sistema


Esta clase contiene toda la informacion necesaria para registrar el objeto, sin crear verdaderamente una instancia del objeto:
import import import j a T / a .r m i . * ; j a v a . rmi . a c t i v a t i o n . * ; j ava. u t i l . Properties; RegisterIt

~ , ~ ~ b cll i as cs

p u b l i c s t a t i c v o i d m a i r ~ ( S t r i r ~a ~rgg s [ ] ) t h r o w s E x c e p t i o r ~ ~ { try i / / I t n s t a l a r url g e s t o r d e s e g u r i d a d System. s e t S e c u r i t y M a n a g e r (new RMISezurityManager i ) ) ;

Procesamiento distribuido con RMI

/ / Crear el grupo Properties env = new Froperties ( ) ; env.put ("java.security.policy", "file://%BOOK HOME%/Ch03/Activatable/ activation/reqisterit.policy"); ActivationGroupDesc myqroupdes = new ActivationGroupDesc (ertv, null) ; ActivationGroupID mygroupid = ActivationGroup.getSysteni().
registerGroup(rnygroupdes);

Activatior~Group.createGroup(myqroupid,mygroupdes,

0);

/ / Crear los detalles sobre el objeto Activatior~Desc obj ectdesc = new ActivationDesc ("HelloServer", "file://%BOOK HOME%/Ch03/Activatable", null);

/ / Registrar el descriptor de activaci6n con el activador HelloIrlterface rnyobject = (HelloInterfacejActivatable .reqister(objectdesc); / / Asiiclar el stub a un r~ornbre del reqistro rmi Naming. rebind("helloObject", myobject);
/ / Salir Systern.out .println ( " D o r ~ e "; )

Casi hemos terminado. Ahora podemos utilizar el viejo cliente que grabamos para nuestro ejemplo inicial y ejecutarlo con 10s mismos argumentos de politica y arranque:
import
]

a v a .rrni . * ;
[

public class HelloClient

public static void rnain(Strinq arqs[]) { if (arqs.length < 1) { System.out.println ("Usage: java HelloCllent <host>"); System. eslt ( I ) ; 1 else { try I HelloIrlterface server
( H e l l v 1 n t e r f a c e ) N a r n i n g . lookup (

"rmi://" + arqs[O] + "/helloObject"); System.out.println(server.sayHello()); catch (Exception e ) [ e.printStackTrace ( ) ;

1 1

i
I

Compile 10s archivos y despuis genere 10s stubs y 10s skeletons para el objeto remoto. Inicie el sistema de Activaci6n utilizando la utilidad r m i d y luego inicie nuestro programa que registra nuestros objetos activables:
rmid J - D j a v a . s e c u r i t y . p o l i c y = r e q i s t e r i t . p o l i c y

Capitulo 3
Ahora podelnos ejecutar el a r c h i w Regis t e r I t:
j

- P j - r ~ ~ . : : e , : ' ~ r i t ! ; . p ~ l i r 2 y = r ~ ~ t? .i p ~r t. e l ir c iy -Cmi ;1'.>a. r m i : : e ~ . i e r .r : . ~ . . l e b r 7 . c r . = f i 1 //3;E?OOi':_ e: HOPlL'i/i'hlj?/A~:t i v ~ L a t , l ~ / Ke~i:?rcrIt

Finalmente, podemos utilizar el clientc, c o m o rnucstra la siguicnte pantalla de salida:

jese en que deberia tener tres o cuatro ventanas d e lineas de comandos abiertas para este ejemplo:
J Rmiregistry

J Rmid

L l RegisterIt
1 3 Helloclient

Las dos ultimas podrian ejecutarse en una ventana.

Alternativa a ampliar la clase Activatable


En ocasiones puede que n o sea posible ampliar la c l a s e ~ civatable t si el objeto remoto necesita ampliar otra clase. Por ejemplo, si estamos escribiendo un applet que queremos convertir e n activable o e n objeto remoto, nuestro applet necesitaria ampliar j ava .applet .Applet y e n Java n o existe la herencia rndtiple.

Ya henios visto anteriurmente que era posible convertir un objeto en remoto exportando el objeto
directamente utilizando uno de 10s mktodos d e exportaci6n de la clase j ava rmi .UnicastRemoteObj ect,envezdeamp~iar~ac~ase~nicast~ernote~bj ect.

Esiste una alternativa similar para 10s objetos activables. Al hablar sobre descriptores de activation hemos mencionadu un metodo exportob j ect ( ) Es posible registrar y exportar un objeto invocando cualquiera de los niCtodos de exportacion d e la clase j ava .Activation .Activatable.

Rescribamos nuestra clase activable Helloserver para demostrar esto, manteniendo igual el resto:

puhlic

class HelluServer

impl.ements H e l l o I n t e r f a c e

puhlic

H ~ l l o S e r v e r [ A c t i v a t i c ~ n Iid, t~ tht-ows RemoLeExcept l o r ] (

Marshaledobject

data)

/ I R e q i ~ t r a r l o y e x p n r t a r l o e n u n puerto anbnlrno Activatable.export0bject [ t h i s , i d , 0 ) ; / / OF,


/ &

Procesamiento distribuido con RMI


Activatable. r-xpsrt0bject(this, id, 0 , new S o r n e R M I C l i e n t S o c k e t F a c t ' 5 r y c s f 0 , new S n r n e R M I S e r v e r S o c k e t F a c t n r y ( ) ) //OR Activatable.exportObject(this, " . " , data, false, 0 ) ; //OR P.ctivata~le.exportObject(this, data, false, 0, new S o r n e R I ~ I I C l i e n t S o c k e t F a c t o r y ( new S n r n t R M I S e r v e r S o c k e t F a c t o r y ( */
'I.",

) ) ;

public Strir,g ~ a y H e l l ~ !ttlrk?ws ) RemoteExcey;tinr~{ return "Hello Igi'~-ld, the current system timr i-" i

r~ew Date ! ) ;

En el ejemplo anterior, dos de 10s constructores presentados tornan factorias de socket como argumentos. Trataremos las factorias de socket en breve. Por ahora, s610 recuerde que puede pasar factorias de socket como argumentos a sus objetos activables.

lniciar multiples JVMs sin recurrir a rmid


r m i d o el activador mismo es un objeto remoto y se ejecuta en una JVM. Cada objeto que es activado es activado en su JVM del grupo de activaci6n pero, en ocasiones, puede ser deseable producir una JVM independiente para cada objeto activable (por ejemplo, en una gran aplicaci6n desearia eliminar el h i c o punto de fallo aislando objetos en diferentes JVM). Es muy sencillo si tenemos en cuenta lo que mencionarnos a1 referirnos a A c t i v a t i o n G r o u p I D , es decir, "Todos 10s objetos con el mismo A c t i v a t i o n G r o u p I D son activados en la misma JVM". Para iniciar mdtiples JVM, el objeto debe tener un A c t i v a t e G r o u p I D diferente o, en otras palabras, debe estar en un grupo de activaci6n independiente. El siguiente c6digo muestra c6mo el mismo objeto H e l l o S e r v e r es registrado de forrna distinta de mod0 que cada objeto tenga u n A c t i v a t e G r o u p I D diferente (y, por consiguiente, un grupo de activaci6n diferente). ~ s t es a la clase que registra nuestros objetos activables:
import j ava. rmi. + ; import java. rmi. activation.+; import java.uti1. Properties; public class RegisterIt { public static void rnain(Strir1g [ 1 a r g s ) { try I //Instalar un gestor de seguridad Systerr~.setSecurityMarlager ( n e w RMISecurityl4anager (
//

) ) ;

crear otra para una nueva VM Properties erlv = new Properties ( ) ; env.put ( " java. s e c u r ~ t y Y p o 1 i c y Y ' , "file://%BOOK HOME%/Ch03/Activatable/MultiVM/ registerit.policy"); ActivationGroupDesc mygroupdes = new ActivationGroupDesc [er~v, r~~lll) ; ActivationGroupID mygroupid = A c t i v a t i o n G r o u p . g e t S y s t e r n ( ) .registerGroup(mygroupdes); ActivatinnGroup. createGroup (mygr~1upii3,rnygroupdes, 0 ); ActivatinnDesc objectdesc = new ActivationDesc ("HelloServer",

Capitulo 3
"file://%BOOK HOME%/Ch03/Activatable/MultiVM/", null ) ; HelloIrlterface myobject == (HelloIr~terface)Activatable.register( obj ectdesz); Naming. rebind ("hello0bjecttt,myobject) ;
/ / Registrar otro id de grupo ActivationGroupID mygroupid 2 ActivationGroup.qetSystem() . registerGroup (niygroupdes) ; ActivationDesc objectdesc 2 = new ActivationDesc("HelloServer", "file://%BOOK HOME%/Ch03/Activatable/MultiVM/", riul l ) ; HellcInterface myobject 2 = (HelloInterface)Activatable.rtqister( obj ectdesc 2) ; Naming. rebind ("helloobjectp2", myobj ect-2) ;
=

catch (Esceptior~t ) [ System.i'ut .prir~tlrj fe); e.prir~tStackTrace ( ) ;

El cliente inicia la nueva JVM en el servidor debido a la activaci6n lenta (activaci6n la primera vez que el
metodo es invocado):
impf~rt j ava. rml. * ; public class HelloClient
{

public statiz void main(Strir1g args[l) 1 if (arqs.length < 1 ) { System.out.println ("IJsaqe: java HelloClient <host>"); System.exit(l); try 1 Hellotr~terface obj

(HeLloInterface)Namlng.lookup( "rmi://" + args[O] + "/helloObjectn); System.out.println(,>bj .sayHeIlo() );


=

/ / Producir la sequnda VM en el servidor HelloInterface obj 2 = (HelloInterface)tlaminq.lookup( "rmi://" t arqs[O] t "/helloObject 2"); 2;j)i o lH l y e a s. 2 j b o i n lt n ir p .t u o m e .ts y S j b o ( sayHe110 ( ) ) ; System.out .prir~tln
}

catch (Exception e) { System.out .println ("HelloClier~texception: " e.printStackTrace ( ) ;

e.getMessage (

) ) ;

i
1

Si ejecutamos este ejemplo v observamos 10s procesos a1 ejecutar el cliente, veremos que se utilizan dos VM de Java:

Procesamiento distribuido con RMI

Archivo

Opciones

-I

--

--

--

--

Nombre de lmagen

Nombre de usuarlo

CPU

Uso de

...

explorer.exe java.exe

Isass.exe mstask. exe NAVAPSVC.EXE NAVAPW32.EXE NPSSVC.EXE ns-admin-exe ns-slapd.exe Psp.exe realplay .exe U M o s t r a r procesos de todos los usuarlos

[xi&ETl

3rocesos: 23

Uso de CPU: 13%

Carga de transacciones: 1740801

Desactivacion
La activaci6n permite a un objeto ser iniciado a petici6n; sin embargo, no desactiva automiticamente un objeto. La decisi6n de desactivar un objeto queda en manos del mismo objeto. U n objeto activable puede desactivarse a si mismo invocando el metodo Activatable.inactive(ActivationID i d ) . Es importante saber la diferencia entre eliminar un objeto del registro y desactivar un objeto. La desactivaci6n es un estado temporal, permitiendo al sistema de activacih reiniciar el objeto mis tarde, mientras que a1 eliminarelobjeto m e d i a n t e ~ c t i v a t a b l e . u n r e g i s t e r ( A c t i v a t i o n I D i d ) , iste queda eliminado permanentemente del sistema de activaci6n. O t r o m i t o d o utilesel m e t o d o ~ c t i v a t a b l e . u n e x p o r t O b j e c t (Remote o b j , b o l e a n f o r c e ) que puede utilizarse para deshacer la exportaci6n del objeto. El b o o l e a n o es utilizado para forzar al objeto a ser no expoetarse incluso si hay llamadas pendientes o en progreso.

Caoitulo 3

Aunque la activation puede ser u n gran avance en rendimiento cuando el numero de objetos de u n sistema es alto, aliviando el drenaje de 10s recursos, debe tener cuidado a1 decidir corn0 y cuindo utilizarla. El sobregasto necesario para crear y reactivar un objeto inactivo es importante. Puede suponer crear una nueva JVM, cargar, verificar clases y deserializar u n estado de objeto persistente. U n objeto deberia normalmente decidir en tiempo seguro mantenerse vivo. Una buena estrategia de desactivacion podria basarse en el tiempo transcurrido desde la ultima Ilamada.

A continuacion, dirigiremos nuestra atencion a la capa Secure Sockets (SSL). Esta section presupone que
el lector esti familiarizado con 10s Sockets T C P I I P y la redificacion en Java.

Sockets de adaptacion y SSL


U n socket es un extremo de comunicacion. Dos sockets en colaboraci6n, uno en la miquina local y el otro en la miquina remota, forman una conexion. Esta distincion entre sockets y conexiones es muy importante. Hay dos tipos de sockets, sockets de conexi6n y sockets de escucha, tambiin conocidos como sockets cliente y servidor, respectivamente. U n socket de conexion existe en cada extremo de una conexion T C P abiertay es abstraido por las clases j a v a . n e t . S e r v e r s o c k e t y j a v a . n e t . s o c k e t . U n socket de escucha no e s t i asociado a ninguna conexi6n T C P per0 solo existe como una abstraction para permitir al nucleo T C P decidir q u i proximas conexiones son aceptadas y quiin obtiene el nuevo socket de conexion aceptado. En cualquier momento, RMI tiene algunos sockets de escucha, uno para cada puerto escuchador (normalmente solo uno porque RMI exporta todos 10s objetos en el puerto "por defecto" si n o se especifica un puerto concreto en el mitodo e x p o r t ( ) examinado anteriormente). RMI tambiin crea sockets de conexion para conexiones de salida y para conexiones de entrada. El numero de conexiones de salida solo depende del numero de llamadas de salida concurrentes. La sencilla regla es la siguiente:

o Si un hilo quiere realizar una llamada remota y todas las conexiones a1 extremo estin en uso,
entonces el RMI abre una nueva conexion para transportar la llamada
0

Si una conexion e s t i libre (es decir, si n o hay ninguna llamada en progreso utilizando la conexion), entonces el RMI la reutilizari para la siguiente llamada remota

RMI produce un hilo para escuchar cada socket de escucha (normalmente tambiin uno). Cuando RMI acepta una nueva conexion, crea un nuevo hilo (y un hilo controla la nueva conexion y el otro vuelve para aceptar una nueva conexion). Cuando la conexion se cierra, su hilo asociado tambiin se cierra. Los hilos de control de conexiones producidos por RMI n o estin de ning6n mod0 serializados. Si las llamadas llegan a la vez, son ejecutadas en hilos concurrentes. Las llamadas todavia pueden sincronizar objetos Java per0 RMI n o realiza esa sincronizaci6n de forma automitica (el objeto remoto es responsable de su propia sincronizacion, ya sea por mCtodos sincronizados o por bloqueo sincronizado). U n punto habitual de confusion es que si el stub remoto es devuelto por una llamada remota, el cliente puede en ocasiones realizar dos conexiones a1 servidor. Esto ocurre porque el subsistema distribuido de recolecci6n de residuos necesita realizar una llamada D G c d i r t y ( ) para notificar a1 servidor que una nueva entidad alberga una referencia a1 objeto remoto.

Procesamiento distribuido con RMI


Puede utilizar netstat para controlar 10s sockets de escucha. La siguiente captura de pantalla muestra 10s sockets justo despuis de que se inicie el registro en 1099. Helloserver es exportado a 2000 y esta' asociado a1 re~istro. La columna de la izauierda enunzera 10s sockets abiertos de la ma'nuina. La u primera linea es para el registro, la segunda para el objeto. La tercera muestra que un socket ha sido abierto por el objeto a1 registro y la riltinza linea nruestra el socket abierto por el registro a1 objeto.

Una n~ejora notable que ha sido afiadida a RMI desde la entrega 1.2 de Java ha sido la capacidad de utilizar factorias de sockets de adaptaci6n basados en el modelo de disefio Factory. En lugar de utilizar 10s sockets convencionales en TCP/IP, cada objeto tiene la capacidad de utilizar su propio tip0 de socket. Esto permite al objeto procesar datos (cn vez dc pasnrlos simplemente), ya sen antes de ser enviado al socket o despues de ser recibido por Cste. En J D K l.l.x, fue posible crear un.1 subclase de adaptation j ava . rml .RMISocket Factory que produjo un socket d e adaptaci6n. difcrcnte a 1ava .net . Socket,para ser utilizado por la capa de transporte de RMI. Sin embargo, n o fue posible para la factoria de socket instalada producir diferentes tipos de sockets para diferentes objetos. Por ejemplo, en J D K 1.1, una factoria de socket de RMI n o podia producir sockets Secure Sockets Layer (SSL) para un objeto y utilizar el Java Remote Method Protocol (JRMP) directaniente sobre T C P / I P para un objeto diferente en la misma JVM. Adenlis, antes de la versi6n 1.2, era necesario que rmiregist ry utilizara hnicamente el protocolo de socket de adaptaci6n del usuario. La factoria d e socket afectaba a1 sistema completo y n o s61o a un objeto. Para entender q u i significa realmente esta afirmaci6n, veamos primer0 donde intervienen 10s sockets de arquitectura M I , sus tipos y sus prop6sitos: Posici6n Rcgistro RMI Socket d e servidor Abre un socket d e servidor (puerto por dcfecto 1099) y espera solicitudes de:
U Servidores para asociar, reasociar,

Socket d e cliente Utiliza un socket de cliente para establecer una conexi6n a un objeto servidor justo despues de haberse registrado.

y desasociar in~plementaciones de objeto.


Clientes que desean localizar servidores. Servidores RMI (implementaci6n remota). Abre un socket de servidor en un puerto especificado por el usuario via m i t o d o exportOb j ect ( ) o, por defecto, a un puerto local aleatorio; es utilizado para aceptar conexiones de las res uestas enwadas por el cliente (el s t u t ) . N o s e utiliza. U n socket d e cliente es utilizado mientrasseconectaalre istro,en concreto para registrar a implementaci6n del servidor.

Clientes RMI (objetos que invocan metodos remotos).

Los sockets de cliente son utilizados para la comunicacion con el registro RMI, ara localizar la implementacidn i e servidor araconseguirqueelrnktodoRd l a m e a1 servidor.

Capitulo 3

/'

,
>.

-1
,~Naming.bind('HelloSe~eV, obj;) \

Objeto
_ , , '

1 ';

,remOto I'

'

!
I

Socket de servidor

Socket de S e ~ d 0 Ir

9I
Devuelve el stub

Socket de cliente

1
-

. Cl~ente 1 - - Invocac~on de metodo


-

13

Cuando un cliente ejecuta una operaci6n de "blisqueda", se realiza una conexi6n a1 socket de servidor en el r m i r e g i s t r y . En general, puede crearse o no una nueva conexi6n para una llarnada rernota. La capa de transporte RMI acumula conexiones para usos futuros. Si alguna conexi6n existente, y a1 menos una de ellas esti libre, entonces se reutiliza; de no ser asi, la implementaci6n actual crea sockets adicionales a peticibn. Por ejernplo, si un socket existente esti siendo utilizado por una llamada existente, entonces se crea un socket nuevo para la nueva Ilamada. Normalmente, hay como minimo dos sockets abiertos puesto que el recolector de residuos distribuidos necesita realizar llamadas remotas cuando 10s objetos remotos son devueltos desde el servidor. Un cliente no tiene control explicit0 sobre las conexiones a un servidor, ya que las conexiones son gestionadas en el nivel de la capa de transporte RMI. Las conexiones expirarin si se mantienen sin utilizar durante un tiempo. Corno puede ver, existe un numero de puntos de comunicacidn y sockets que son utilizados en este proceso de comunicacidn de tres vias entre el cliente, el registro y el objeto. Es tambikn importante destacar que el registro s61o es necesario para localizar un objeto por su nombre. Una vez que el objeto esti localizado, hay comunicaci6n directa entre el objeto y el cliente. U n objeto puede especificar que clases de factoria son necesarias para que alguien se comunique con este tipo de socket a travts del constructor j a v a . r m i . s e r v e r . U n i c a s t R e m o t e O b j e c t ( o j a v a . r m i .a c t i v a t i o n . A c t i v a t a b 1 e para ese asunto). Instancias de esas factorias s o n u t i h a d a s para crear instancias de 10s tipos de sockets deseados:
protected UnicastRernoteObject(int port, RMIClientSocketFactory RMIServerSocketFactory ssf) csf,

C o m o hemos explicado en la tabla anterior, una vez que el cliente ha localizado un objeto, utiliza un socket de cliente para conectar a1 socket de cliente que esti escuchando el objeto. La factoria de socket de cliente debe implementar la interfaz j a v a . r m i . s e r v e r . m I S o c k e t F a c t o r y . Elsocket de cliente es creado desde esta instancia d e ~ ~ ~ ~ o c k e t ~ invocando a c t o el r ~ m k t o d o c r e a t e s o c k e t ( ) que devuelve una instancia del tip0 de socket adaptado al servidor y a1 puerto especificados:
public Socket createsocket (String host, int port)

La factoriadesocket deservidordebeimplementarlainterfazj a v a .r m i .s e r v e r . R M I S e r v e r S o c k e t F a c t o r y y proporcionar una implernentaci6n para el metodo c r e a t e s e r v e r S o c ke t ( ) . El socket de servidor es creado (para empezar a escuchar llamadas entrantes) invocando la implernentacion de rnetodo en la clase de factoria de socket de servidor:

Procesamiento distribuido con RMI


public Serversocket createServerSocket(int port)

Esto es especialmente fitil cuando se desea cifrar la comunicaci6n entre 10s objetos. Por ejemplo, utilizando SSL o TLS. Examinemos un ejemplo de c6mo se puede realizar. Primero necesitariamos un par de cosas, siendo la principal un proveedor de seguridad que proporciona una implementaci6n del protocolo SSL en Java. Muchos productos terceros disponibles hacen esto. SSL y TLS proporcionan ambos cifrado y certificaci6n. En realidad, Transport Layer Security (TLS) es la nueva norma de Internet Engineering Task Force (IETF) y est6 basada e n SSL.
Las especificaciones SSL puede encontrarlas en http:llhome.netscape.comlenglsecurityl y las especificaciones TLS se encuentran en RFC 2246 en http:llwww.ieff.org.lrfclrfc2246.&t. Los detalles sobre las implementaciones SSL de fuente abierta (SSLeaylOpenSSL) puede encontrarlas en http:llwww. opnessl. org. ,

Sun ofrece Java Secure Sockets Extension USSE) que implements una versi6n Java de 10s protocolos SSL y TLS e incluye funcionalidad para el cifrado de datos, autentificacidn de servidor, integridad de mensaje y autentificacion optional del cliente.
El ejemplo examinado aqui utiliza JSSE. Necesitara' descargarlo de f o n a independiente para J2SE (1.2 o 1.3) y sera'n incluido en J2SE (1.4), vkase http://java.sun.com/products,!jsse/para ma's infonacidn.

Se va producir un rendimiento suplementario y la comunicaci6n va a ser muy lenta debido a la complejidad del acuerdo inicial y el cifrado que supone. El mod0 en el que el proveedor implementa el algoritmo afectari tambiin el rendimiento. Por ejemplo, una implementation nativa como GoNative Provider (http:/ /www.rtfm.corr\/puretls/gonative.html) es mis ripida que su equivalente Java. Intenternos primer0 analizar quC parte de la comunicaci6n queremos/necesitamos cifrar. El registro de designaci6n es implementado como un servicio RMI estindar por lo que 10s intentos de registrar y buscar servicios supondrin el establecimiento de conexiones de red. Si necesita que la comunicaci6n con el registro tenga lugar en sockets seguros, el registro de designaci6n obviamente necesitari escuchar sobre sockets seguros de servidor. U n mod0 muy direct0 de conseguirlo es que el servidor inicie su propio registro de designacion. Este registro se beneficiari entonces del apoyo SSL del servidor. El servidor necesitari invocar y configurar explicitamente una factoria de socket e iniciar el registro:
RMISocketFactory.setSocketFactory (some vendor provided factory); LocateRegistry.createRegistry(somep~rt);

La factoria de socket SSL puede entonces ser instalada en el cliente antes de buscar el objeto y todo quedari asegurado por SSL. Puesto que el mismo socket n o puede escuchar en dos puertos, seria necesario ejecutar dos registros: u n o seguro y u n o normal, si necesitara buscar e n diferentes protocolos. La mayoria d e 10s vendedores proporciona u n registro seguro con la implementaci6n Java-SSL que puede ser utilizado si n o estd iniciando el registro programdticamente. En la mayoria de 10s casos, s6lo es importante y necesita cifrado la comunicaci6n entre 10s objetos, no la bGsqueda; esto es lo que estudiaremos en el siguiente ejemplo. Para que la comunicaci6n tenga lugar sobre

Capitulo 3
SSL o TLS, necesitamos dos cosas: claves y certificados. Para mis informaci6n sobre estos dos elementos, consulte 10s vinculos a la documentaci6n SSL y TLS.
Antes de seguir adelante, generamos4as claves y certificados utilizando la utilidad JDK k e y t o o l . ~ s t es a una herramienta de gesti6n de certificados utilizada para gestionar pares de claves pfiblicas/privadas y certificados asociados que deben ser utilizados en auto-autentificacih y en servicios de integridad y autentificacidn de datos, utilizando firmas digitales. En un entorno comercial, probablemente utilizaria k e y t o o l para generar una solicitud de certificado y utilizaria esa solicitud para obtener un certificado de una Autoridad de Certificados (CA) como Verisign (http://www.verisign.com). Para nuestros prop6sitos, generaremos un certificado autofirmado (un certificado de la CA autentificando su propia clave pliblica). En otras palabras, utilizaremos nuestras propias claves y certificados utilizando la opci6n - g e n k e y en k e y t o o l . Ejecute la utilidad k e y t o o l con parimetros similares a istos:

Podemos coniprobar el certificado utilizando k e y t o o l de un mddo distinto:

Esto genera un almacin de claves llamado " w r o x " que contiene las claves y el certificado auto-firmado y contiene la contraseiia "secreta".

Consulte la documentacidn adjunta a J D K para m i s detalles sobre c6mo utilizar kqytool, las claves y 10s certificados en la arquitectura de seguridad de Java 2.
Finalmente, tambiCn exportamos el certificado generado a un archivo c l i e n t i m p o r t . cer para el uso de clientes que u t i l i c e n k e y t o o l :
L : e y ~ c ~ , =-~ elx ~ ' r . i t -t:eystore %BOOK_HOME%\Ch03\SSL.\. k e y s t o r e s e c r e t - f i l e c l l e n t i m p o r t . c e r -alias w r o x
-store$ass

Recuerde que n o estamos utilizando SSL basado en navegador en ningkn fragment0 de estos ejemplos. Si desea utilizarlo, necesitard generar certificados con el algoritmo RSA (utilice la opcidn -keya lg en keyt 001).Para esto, necesitard instalar un proveedor que ofrezca la implementacidn del algoritmo RSA puesto que J D K 1.2 n o se ajusta a esta implementacidn. Para nuestros propdsitos, el proveedor JSSE contiene una implementacidn y el apoyo RSA estd incorporado en J D K 1.3. Tambibn, la implementaci6n J C E de libre distribuci6n disponible en http://www.openjce.orges un buen proweedor de API de seguridad.
Volvamos ahora a1 ejemplo H e l l o w o r l d que utilizamos anteriormente y rescribimoslo, para asegurar la comunicaci6n de objeto a objeto. D e nuevo, la interfaz remota se mantiene igual:

Procesamiento distribuido con RMI


import java.rmi.Remote; import java.rmi.RemoteException; public interface HelloInterface extends Remote { public String sayHello ( ) throws RernoteException;

Ahora rescribimos la implementaci6n remota de esta interfaz:


import j ava. rmi . * ; import java.rmi.server.UnicastRemoteObject; import java.uti1. Date; public class HelloServer extends UnicastRemoteObj ect implements HelloIrjterface { public H e l l o S e r v e r O throws RemoteException { super ( 0 , n e w MyClientSocketFactory ( ) , n e w MyServerSocketFactory

( ) ) ;

I
public String sayHello() { return "Hello World, the current system time is
"

t new Date();

I
1

Observe que la h i c a diferencia es que pasamos nuestras propias factorias de adaptaci6n que serin utilizadas para este objeto en lugar de las factorias por defecto. Ahora utilizamos el mismo programa que utilizamos antes para registrar este objeto remoto:
import j ava. rmi. + ; public class RegisterIt
{

public static void main(String a r g s [ ] ) [ try 1 / / Ir~stanciar el objeto HelloServer obj = n e w HelloServer ( ) ; System. o u t .println ("Object instantiated" tobj ) ; Naming. rebind ("/HelloServer", obj ) ; System. o u t .println ("HelloServer bound i n registry" ) } catch (Exception e) { System.out.println(e);

I
I

Estas sentencias que hemos pasado tan ficilmente son las factorias de sockets. Examin6moslas ahora en detalle. La c l a s e ~ ~ ~ e r v e r ~ o c k e t y ~ es ac utilizadapara tor crear instancias del socket de servidor en el puerto a1 que fue exportado el objeto. Esta clase debe implementar la interfaz j a v a . rmi .server. ~ ~ ~ ~ e r v e r ~ o c k e t ~ a debeserserializable ctoryy (parafacilitarposibles transportes en la red). El intercambio seguro entre el cliente y el servidor conlleva un intercambio de claves y certificados y el socket creado debe primer0 inicializar la comunicacidn con el cliente antes de intercambiar ningGn dato. La implementaci6n JSEE nos permite realizar esto en unas cuantas lineas de c6digo. Abrimos el almacin de claves (que hemos generado) del archivo utilizando su contraseiia, inicializamos la implementaci6n SSLITLS y devolvemos una instancia de un socket seguro:
import import import import import j a v a .i o . + ; j ava. net. + ; j a v a . rmi. server. + ; java.security.+; javax.net. s s l . + ;

Capitulo 3
import javax.security.cert.*; import com.sun.net . s s l . + ; publlc class MyServerSocketFactory implements RMIServerSocketFactory, Serializable { / / Implementar el metodo d e interfaz publlc Serversocket createServerSocket(int port)throws IOException { SSLServerSocketFactory s s f = null; try i / / Configurar el gestor de seguridad para la autentlficacibn de servldor char [ I passphrase = "secret". toCharArray ( ) ; Obtener un contexto para el protocolo. Podemos utilizar SSL o TLS seg6n sea necesario ( " T L S " ); SSLContest ctx = SSLContext. getIr~stance KeyManagerFactory k m f = K e y M a n a g e r F a c t o r y . g e t I n s t a r ~ c e ( " S u n X 5 0 9 " );
/ / Abrir el almacen d e claves con la contraseAa / / e inicializar el contexto SSL con este alrnackn d e claves KeyStore k s = KeyStore.getInstance ( " J K S " ); ks. load ( n e w FileInputStrearn keystore"), passphrase) ; kmf.init(ks, p a s s p h r a s e ) ; ctx. init (krnf.getKeyMar1agers ( ) , null, null); s s f = ctx.getServerSocketFactory ( ) ; catch (Exception e ) { e.printStackTrace0;
( ' I .

//

I r e t u r n ssf.createServerSocket(port);

La factoria de socket de cliente es utilizada para crear instancias de 10s sockets de cliente que conectan alas instancias de 10s sockets de servidor generados en la factoria anterior. Se supone que el proveedor JSSE tarnbikn esti instalado en la rniquina cliente:
import import import import
j ava. io. + ; j ava . net. * ; java.rrni.server.*; javax.net.ssl.*;

public class MyClientSocketFactory public

implemerlts RMIClientSocketFactory, Serializable {


{

Socket createsocket (String host, int port) throws IOException

/ / Obtenemos la factoria d e socket SSL por defecto. SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault(); SSLSocket socket = lSSLSocket)factory.createSocket.(host, port); return socket;

El cliente se rnatiene igual:


import java.rmi.Narning; import ]ava.rmi.RemoteExceptian; public class Helloclient
{

public static void main(String a r g s [ ] ) { if (args.length < 1 ) {

Procesamiento distribuido con RMI


System.uut .println ( " U s a g e : j a v a System.exit{l); Helloclient
<host>" ) ;

1
try{
"rmi://" t args[O] + "/HelloServer"); S y z t e m . o i ~ t . p r i n t l n["Got a r e m o t e r e f e r e n c e " + obj ) ; Systern.out .prlntlr~iobj .sayHello()); catch (Exception e ) 4 System.out.println(e);
HellaIntetfacr
nb]

= !HelloIr~terface)Elaming l .u o k u p (

El archivo ssl .policy que utilizarnos aqui es en realidad el misrno que utilizarnos en 10s ejemplos an teriores:
grant [ permission java. secutity.Al1Permission;

Ahora podemos cornpilar las clases y generar 10s stubs para Helloserver utilizando el rmic ernpaquetado con el JDK.

Es preciso exarninar dos pequeiios detalles antes de ejecutar el ejernplo. Para que el cliente interactue e intercarnbien contraseiias y certificados con el servidor, debe confiar en el proveedor del certificado
digital. En otras palabras, conio nuestro certificado es auto-generado, la mdquina virtual cliente debe: Importar explicitarnente el certificado en el almacen de claves que esti utilizando y rnarcarlo corno certificado confiable Utilizar el rnisrno alrnackn de claves que utilizanios en el servidor Para la segunda opcibn, el proveedor JSEE debe ser instalado en la rndquina cliente (si es diferente del servidor) en uno de dos rnodos posibles:
0 Estiticarnente en el archivo j ava .security 0 Dinirnicamenteutilizando~ecurity. addprovider (new com.sun.net.ssl.internal.ss1.Provider 0 ) ;

Para detalles m b espec$cos sobre estos me'rodos de ins&alnci6n, el lector puede recwrrir a la docwmenmcicin JSSE.

El cliente puede iniportar el certificado desde el archivo que hernos generado anteriormente, clientimport. cer, al alniacCn de claves que esti utilizando y rnarcarlo corno confiable utilizando keyt ool con la sentencia -import:

Capitulo 3
Una vez realizado esto, primero necesitamos iniciar el registro en el servidor (ejecutar rmiregistry):
rniire<~i.stry -J-Djava . s e c u r i t y . ~ ~ r . l i c y = s s l . ~ " ~ L i c y

registrar entonces el objeto con el registro:


1;1.:a - c l a s s ~ a t h % C L A S S P A T H S - U j a v a . . s e c u r i t y . ~ c ~ l i c ~ ~ = . pc, '?~ Lli c y Es]ava. r r n i . s ~ r v e r . c ~ ~ ~ e k a i l ~ = f i 1 r : / / r (lH BO O MO E+ ~/ 1 3 h O ? / S - C L / R?qi~trrIt

Recuerde instalar con cuidado JSEE. Ponga 10s archivos jar en su localizaci6n <JAVA-H~ME>\lib\exte instale el proveedor en su archivo java. Security (viase el archivo INSTALL.txt dentro del lote JSEE para rnis detalles). Si tiene mliltiples entornos de period0 de ejecucion, aseglirese de editar el archivo de seguridad correcto. La solucion rnis sencilla es configurar el PATH para que s61o apunte el JDK que esti utilizando.

Ahora ejecute el cliente y especifique,el aln~acen de claves a utilizar utilizando la propiedad JSSE j a v a x . net. ssl . truststore. Este es el~lmackn de claves en el que ha sido importado el certificado o el mismo almacen de datos como servidor.

Si queremos que el cliente sea un applet, necesitamos primer0 resolver algunos puntos de configuration:
3 El cliente debe tener una JVM J2SE 1.2 (o posterior). En el momento de publicaci6n de este libro, Netscape 6 y 6.1 son 10s Gnicos navegadores con soporte J2SE 1.2. Por lo tanto, probablemente

necesitemos instalarel mddulo complementario de Java. (Este mddulo es de descarga Gnica y actualiza automiticamente laJVM del navegador a la Gltima versi6n. Funciona tanto con IE como con Netscape.)
U La JVM cliente debe tener el almacen de claves y 10s certificados adecuados instalados.

0 La JVM cliente deberia tener la politica correcta, permitiendo que 10s sockets sean abiertos de nuevo al servidor. 0 La JVM cliente deberia tener el proveedor de seguridad instalado o tener 10s permisos de seguridad adecuados de mod0 que pueda instalarse un proveedor de seguridad dinimicamente.

O Puede acceder a mls informaci6n y descargas para el modulo complementario de Java en http:// java.sun.com/products/pluginl.

Procesamiento distribuido con RMI


Examinemos el siguiente applet. Es sencillo, similar a1 ejemplo que hemos visto antes, except0 que se trata de un applet. Es importante captar que el applet n o tiene nada que ver con la configuraci6n SSL del navegador. La conexi6n SSL tiene lugar a nivel del socket RMI. La clase de factoria de socket de cliente es descargada dinimicamente y se realiza la conexi6n segura a1 servidor:
import import import import java.applet.*; j ava. awt . * ; j ava. rmi. * ; j ava. security. * ;

public class SSLHelloApplet extends Applett String message


=

"-n/a-";
=

HelloInterface obj

null;

/ / Obtener una referencia a1 objeto durante el inicio del applet public void init ( ) [ try I Security. addprovider ( n e w com. sun. net. ssl. internal. ssl. Provider ( ) ) ; String host="rmi://" + getCodeBase().getHost() + "/Helloserver"; HelloInterface obj = (HelloInterface)Naming.lookup( "rmi://localhost/HelloServer"); message = obj . sayHello ( ) ; 1 catch (Exception e ) { System.out.println(e);

1
/ / Mostrar un mensaje en el applet public void paint(Graphics g)[ g.drawString(message, 25, 5 0 );

1
1

A continuaci6n, la pigina HTML ( i n d e x . html) para el applet anterior. Esta pigina es convertida
utilizando la herramienta conversora HTML empaquetada con el m6dulo complementario de Java. Cuando un cliente se encuentra con esta pigina, si no existe una versi6n compatible, el JRE 1.3 seri descargado del URL especificado. (La pigina Web de Sun en este caso):

The message from the Helloserver is: <P> <!-"CONVERTED APPLETn-> < ! - CONVERTER VERSION 1.3 -> <object classid = "clsid:8AD9C840-044E-llDl-B3E9-00805F4 99D93" width = 500 height = 120 codebase = "http://java.sun.com/products/plugin/l.3/jinstall-l3win32.cab#Version=l, 3,0,0"> <param name = code value = "SSLHelloApplet" > <param name = codebase value = "http://localhost:8080/hello/" > <param name ="typeu VALUE="application/x-java-applet;version=1.3">

Capitulo 3
< p a r a m n a m e = " s c r i p t a b l e n VALUE="false"> <comment> <embed t y p e = "applica tion/x-j ava-applet;version=l - 3 " c o d e = S S L H e l l o A p p l e t " c o d e b a s e = "http: / / l o c a l h o s t : 80RO/hello/" w i d t h = 500 h e i g h t = 1 2 0 scriptable=false pluginspage = "http://ja~a.sun.com/products/p1uqin/l.3/ plugin-install.html"> <noernbed></comrnent>

< !<applet code = "SSLHelloApplet" w i d t h = 500 height = 120> </applet> codebase


=

"http://localhost:8080/hello/"

->
<!-"end converted appletW->

Cuando se accede a la pigina anterior desde el navegador, el navegador determina a partir de 10s etiquetas que un plug-in URE 1.3) es necesario para cargar este componente y le insta a descargarlo desde la ubicacibn especificada en el parimetro pluginspage ( o codebase, dependiendo del navegador); esto es asi, por supuesto, asumiendo que n o esti ya instalado:

Hello World
The mcssaae born OK HelloServu is:

-._.

Una vez descargado e instalado el plug-in y una vez lo hayamos habilitado desde su consola en nuestra miquina, podemos acceder a la misma pigina. El navegador lo cargari entonces en la nueva JVM Java 1.3 (y no en la JVM por defect0 del navegador). Llegados a este punto, necesitamos asegurarnos de que afiadimos 10s padmetros de period0 de ejecucibn necesarios para el plug-in utilizando el applet J a v a P l u g - i n en C o n t r o l P a n e l . Necesitamos aAadir 10s parimetros-Djava. S e c u r i t y . p o l i c y y - D j a v a . n e t .ssl.trustStore.Enesteejemplosedn:

Procesamiento distribuido con RMI

Enable Java Plug-in

B Snow Java Console Ei Cache JARS in memory

Java Run Tittle Parameters

~-0)arasecuritypolic~C:I~roJaaSe~e~ChO3ISSL'r~~lpolic~

Finalmente, debemos obtener u n resultado similar al siguiente:

Hello World, Me current system lime 15 Wed Aug 22 15-1100 FmT*OI 00 2001

Se puede acceder al m i s m o URL u t i l i z a n d o a p p l e t v i e w e r :

Capitulo 3

Hello World, the current system time is Wed Aug 22 12:24:11 GMT+01:00 2001

Applet starled.

RMI, cortafuegos y HTTP


Si ha trabajado en cualquier empresa redificada, probablemente estC familiarizado con como 10s cortafuegos bloquean t i d o el thfico de la red, a'excepci6n de 10s destinados a ciertos puertos "conocidos". Sin embargo, son necesarios para proteger la seguridad de la red. Puesto que la capa de transporte RMI abre conexiones dinimicas de socket entre el cliente y el servidor, el trifico JRMP es normalmente bloqueado por la mayoria de las implementaciones de cortafuego. RMI proporciona un rodeo para esto. Hay tres metodos principales para evitar 10s cortafuegos: Tunelado H T T P
0 SOCKS

Factorias de socket descargadas Examinaremos cada uno de estos mitodos sucesivamente.

Para cruzar cortafuegos, RMI hace uso del tunelado H T T P encapsulando las llamadas RMI en una solicitud H T T P POST. Este mttodo esti muy extendido ya que no requiere apenas configuraci6n y funciona bastante bien en entornos de cortafuego que permiten el manejo de HTTP a travCs de un proxy, pero rechaza las conexiones T C P salientes regulares. Existen dos formas de tunelado HTTP:

H l l P a puerto
Si un cliente esti detris de un cortafuegos y RMI no consigue realizar una conexibn normal a1 servidor, la capa de transporte RMI lo reintenta automiticamente encapsulando 10s datos de llamada JRMP en una solicitud H T T P POST.

Procesamiento distribuido con RMI


Puesto que casi todos 10s cortafuegos reconocen el protocolo HTTP, el servidor proxy especificado deberia poder enviar la llamada directamente a1 puerto en el que el servidor remoto esti escuchando. Es importante que la configuration del servidor proxy sea pasada a la JVM cliente. Una vez que 10s datos JRMP encapsulados en H T T P son recibidos en el servidor, -RMI puede desenvolver automiticamente la solicitud tunelizada H T T P y decodificarla. La respuesta es enviada entonces de vuelta a1 cliente como datos encapsulados en HTTP. La configuraci6n del servidor proxy puede ser pasada utilizando propiedades tales corno:
java

-Dhttp.proxyHost=hostname

-Dhttp.proxyPort=portriumber

Helloclient

El tunelado H T T P puede ser inutilizada configurando la propiedad:

HTTP a CGI
Si n o se puede contactar con el servidor desde el cliente, incluso desputs de el tunelado, porque tambitn este se encuentre detris de un cortafuegos, la capa de Transporte RMI utiliza un mecanismo similar en el servidor. La capa de Transporte RMI sitGa las llamadas JRMP en las solicitudes http y envia esas solicitudes, del mismo mod0 que el mttodo anterior. Sin embargo, en lugar de enviarlas a1 puerto servidor, las envia a http://hostname:80/cgi-binljava-rmi?fo~ward= <port>. Debe haber un servidor H T T P escuchando en el puerto 80 en el proxy, que tiene el script j ava-rmi .cgi. El java-rmi.cgi a su vez invoca una JVM local, desenvuelve el paquete http y envia la llamada a1 proceso servidor en el puerto designado. Las respuestas basadas del servidor en JRMP RMI son enviadas de vuelta como paquetes H T T P a1 puerto cliente originario donde RMI desenvuelve de nuevo la informaci6n y la envia a1 stub RMI adecuado.
El script j a va -rmi cgi esta' empaquetado con J D K y puede encontrarlo en el directorio b i n Para evitar cualquier problema de resobcio'n DNS en el arranque, el nombre calificado completo del host debe ser especificado mediante una propiedad de sistema corno:

Una implementacio'n de serulet del CGI llamada manejador de serulet esta' disponible en Sun en: http:lljava.sun.comlj2sell.3/docslguidelrmilarchiveslrmise~/ethandler.zip.

Otra alternativa a j ava-rmi . cgi es utilizar un redirector de puerto (por ejemplo, DeleGate proxy) en el puerto 80 que acepte conexiones y las redirija inmediatamente a otro puerto. Aunque el tunelado H T T P es una alternativa, en general deberia evitarse por las siguientes razones:
O

Hay una significante degradaci6n del rendimiento. Durante el tunelado, la aplicaci6n RMI n o podri multiplexar las llamadas JRMP en una dnica conexi611, debido a1 paradigma H T T P solicitudrespuesta. redirige cualquier solicitud entrante a cualquier puerto, circunvalando por completo el cortafuegos.

o Utilizar el script java-rmi-cgi (o servlet) es una gran trampa de seguridad en el servidor. El script
0 Las aplicaciones RMI tunelizadas sobre H T T P no pueden utilizar retrollamadas.

El protocolo SOCKS
SOCKS (SOCKet Server) es un protocolo proxy de red que habilita a 10s hosts de un lado del servidor SOCKS para obtener acceso completo a 10s hosts del otro lado del servidor SOCKS sin requerir

Capitulo 3
accesibilidad I P directa. El servidor SOCKS redirige las solicitudes de conexi6n procedentes de hosts situados en lados opuestos de un servidor SOCKS (el servidor SOCKS autentifica y autoriza las solicitudes, establece un proxy de conexi6n y retransmite datos). Por defecto, 10s sockets JDK utilizan un servidor SOCKS si esti disponible y configurado. Sin embargo, 10s sockets de servidor no se ajustan a SOCKS por lo que este enfoque s61o es util para llamadas salientes desde el cliente a1 servidor.

Factorias de sockets descargados


Ya hemos examinado con detenimiento c6mo pueden utilizarse 10s sockets de adaptaci6n. Las clases de factoria pueden codificarse para funcionar alrededor de un cortafuegos. Las factorias de sockets cargados dinimicamente ofrecen una buena alternativa a el tunelado HTTP, per0 para que el c6digo supere el cortafuegos debe ser codificado en las factorias. Esto es posible si tiene una configuraci6n de red fija y sabe c6mo funciona ese determinado cortafuegos. Sin embargo, diferentes clientes pueden tener diferentes cortafuegos y existen distintas cuestiones referentes a derechos de acceso para proporcionar este tunelado y, por supuesto, clases de factoria variables.

RMI sobre Internet Inter-Orb Protocol (IIOP) integra procesamiento distribuido sometido a CORBA (Common Object Request Broker Architecture) directamente en Java. RMI sobre IIOP, desarrollado conjuntamente por IBM y Sun, es una nueva versi6n de RMI para I I O P que combina las sencillas caracteristicas de programaci6n de RMI con la interoperatividad de CORBA. RMI y CORBA han evolucionado de forma independiente como modelos de programaci6n de objetos distribuidos. RMI fue introducido para proporcionar un sencillo modelo de programaci6n para desarrollar objetos distribuidos mientras que CORBA es un modelo de programacion de objetos distribuidos muy conocido que se ajusta a una serie de lenguajes. El protocolo I I O P conecta productos CORBA de diferentes vendedores, asegurando la interoperatividad entre ellos.

El Grupo de Gestidn de Objetos (Object Management Group, O M G ) , visite http:llwww.omg.orgl, es el guardirin oficial de informacidn para C O R B A y I I O P , incluido las especijicaciones C O R B A 2.0 disponibles en http:llwww. omg. orgltechnologyldocumentslspecifications. htm. Adicionalmente, el I D L para representacidn Java se encuentra disponible en http:llwww.omg.orgl technologyldocumentslformallcorba~languagemapping~specs.htm.
RMI-IIOP es, hasta cierto punto, un matrimonio de RMI y CORBA, ya que las interfaces remotas pueden ser escrita's en Java e implementadas utilizando 10s API RMI de Java. Estas interfaces, sin embargo, pueden ser implementadas en cualquier otro lenguaje que se ajuste a una representaci6n O M G y a un O R B surtido por un vendedor para ese lenguaje. De un mod0 similar, 10s clientes pueden ser escritos en otros lenguajes, utilizando IDL derivados de las interfaces remotas Java.

Procesamiento distribuido con RMI

Cl~enteRMI (solo Java)

JRMP

Se~dorRMl (solo Java)

'
1

Cl~ente CORBA
(cualquler lenguaje)

*
llOP

SeNldor CORBA
(cualqulerlenguaje)

ualquler lenguaje)

La figura anterior resume el rnatrirnonio RMI-IIOP. Puede parecer que las flechas que conectan 10s clientes /sewidores JRMP a 10s clientes /sewidores RMI-IIOP estin ma1 situadas porque son protocolos diferentes. Estas flechas estin realrnente donde deben estar porque RMI-IIOP se ajusta a 10s dos protocolos, JRh4P y IIOP. U n o de 10s objetivos iniciales de diseho era conseguir que la rnigracidn a I I O P fuera factible, y de hecho ficil, y evitar la necesidad de un tercer rnodelo distribuido a aprender por 10s desarrolladores. El objeto servidor creado utilizando el API Rh4I-IIOP puede ser exportado corno objeto que se ajusta aJRMP o corno objeto que se ajusta a I I O P sirnplernente carnbiando las propiedades de tiernpo de irnplernentaci6n (sin carnbiar o recornpilar c6digo). RMI-IIOP tarnbikn se ajusta a la exportaci6n dual, lo que significa que un linico objeto servidor puede ser exportado para ajustarse a JRh4P y a I I O P sirnultinearnente.

lnteroperatividad con CORBA


U n cliente Rh4I-IIOP no puede necesariarnente acceder a todos 10s objetos C O M A existentes. La sernintica de 10s objetos C O M A definida en IDL es un grupo de la sernintica obedecida por 10s objetos RMI-IIOP, que es la raz6n por la que un IDL de objeto C O M A existente no puede siernpre ser representado en una interfaz Java RMI-IIOP. S61o cuando la sernintica de un deterrninado objeto C O M A resulta corresponder con la de RMI-IIOP, un cliente RMI-IIOP puede llarnar a un objeto C O M A . La conexi6n entre el cliente RMI-IIOP y el sewidor C O M A es en ocasiones (pero no siernpre) posible. Sin embargo, la cuesti6n no deberia exagerarse porque s61o se aplica a1 tratar con objetos CORBA ya existentes. Fijindonos en la parte inferior de la figura, si disefiarnos un objeto nuevo con una interfaz Java Rh4I-IIOP, podernos realizar las siguientes observaciones:

Capitulo 3
0 La implementacidn CORBA: puede automiticamente generar su correspondiente IDL con la herramienta r m i c . Desde este archivo IDL, puede implementarlo como un objeto CORBA en cualquier lenguaje aceptable, como C + po;ejemplo~~ste objeto C + + es un puro objeto CORBA que puede ser llamado por un cliente CORBA, asi como por un cliente RMI-IIOP sin ninguna limitacibn. Para el cliente RMI-IIOP, este objeto CORBA C + aparece como un puro objeto RMI-IIOP porque esti definido por una interfaz Java RM-IIOP.

0 La implementaci6n RMI-IIOP: el objeto aparece como un objeto CORBA a un cliente CORBA (porque un cliente CORBA puede acceder a 61 a travis de su IDL) y como un objeto RMI para clientes RMI (porque acceden a 61 a travis de su interfaz Java RMI-IIOP).

Resumiendo, la diferencia entre un objeto CORBA y un objeto RMI-IIOP es s d o una cuesti6n de implementacibn. Una de las razones de 10s ~roblemas con 10s obietos existentes mencionados anteriormente es aue dos mejoras significativas de las especificaciones CORBA 2.3 fueron realizadas en realidad para conseguir la interoperatividad de RMI-IIOP y CORBA. O M G acept6 estas especificaciones:
0

Especificaci6n de objetos por valor: este concept0 ya esti definido en Java en forma de Serializaci6n de objetos y esti destinado a conseguir que otros lenguajes implementen un protocolo similar. Especificaci6n de representacibn Java e n IDL: ista es la representaci6n utilizada para convertir las interfaces de Java RMI en definiciones CORBA IDL. N o deberia confundirse con la representacidn IDL en Java definida en CORBA 2.2.

Ambas especificaciones estin disponibles en O M G y tambiin puede acceder a ellas en http://java.sun.com/ products/rmi-iiop/index.html.O M G ha aceptado oficialmente ambas especificaciones para CORBA 2.3 y JDK 1.3 para incluir RMI-IIOP y un compilador IDL en Java.

Escribir programas con RMl-llOP


Existen algunas diferencias de desarrollo en sintaxis aunque el modelo en su totalidad sigue siendo el mismo; significativamente, RMI-IIOP utiliza el API J N D I para localizar y registrar objetos. Aunque el procedimiento de desarrollo para RMI-IIOP es pricticamente el mismo que el de RMI URMP), el entorno de period0 de ejecuci6n es notablemente diferente en cuanto que la comunicaci6n se realiza a travis de un ORB sometido a CORBA 2.3 aue utiliza I I O P Dara la comunicaci6n entre servidores v clientes. Examinemos brevemente estas diferencias.

En el servldor
N o hay ning6n cambio significativo en el procedimiento de desarrollo para objetos RMI en RMI-HOP. Los pasos bisicos y su orden es el mismo que hemos descrito antes en nuestro ejemplo HelloWorld, con algunos cambios que tambiin reflejan el uso de J N D I para buscar y asociar objetos.

import j ava. rmi. + ; import java.uti1 .Date; import javax.rmi.PortableRemoteOb]ect;

La clase de implementaci6n de un objeto remoto:


public class Helloserver extends PortableRemoteObject implements HelloInterface {

Procesamiento distribuido con RMI


El objeto ~ o r t a b l e ~ e m o t ejo eb c t es similar a ~ n i c a s t ~ e m o t e joebc t pero proporcionala funcionalidad de base en el dominio IIOP.
public Helloserver ( ) throws RemoteException { super ( ) ; / / Call the superclass constructor to export this object

I
public Strirtg s a y H e l l o 0 thruws RemoteException { return "Hello World, the current system time is "
t

new Date();

I
0

Genere un vinculo para I I O P con r m i c - i i o p : con la opcibn -i i o p el cornpilador r m i c genera las clases de stubs y vinculos que obedecen el protocolo IIOP. Sin esta opcibn - i i o p , r m i c genera un stub y un skeleton para el protocolo JRMP, o hicamente stubs si tambikn utiliza la opcion - v 1 . 2 (recuerde que 10s skeletons no son necesarios en 1.2). Ejecute t n a m e s e r v . e x e como un sewidor nombre: este sewidor proporciona 10s sewicios I I O P CosNaming para que 10s clientes busquen objetos. clientes CORBA).

0 Genere I D L con r m i c - i d 1 para clientes CORBA (si a nuestro objeto tambikn van a acceder 0 A1 iniciar el sewidor, deben configurarse dos importantes variables de entorno para el contexto

JNDI.

a j a v a . n a m i n g . f a c t o r y . i n i t i a l . ~ s t es e el nombre de laclase autilizar como factoria para crear el contexto.

b.

j a v a . n a m i n g . p r o v i d e r . u r l . ~ s t es e el URLdel sewicio de designacibn, similar a1 formato URL rmi:// descrito anteriormente. El r m i : / / es reemplazado por i i o p : / / y el puerto por defect0 para el registro es el 900 en lugar del 1099.

Estas propiedades pueden ser especificadas bien a1 iniciar el sewidor, como se muestra a continuacibn, o bien codificando 10s valores en j a v a .r m i .P r o p e r t i e s y pasindolo a I n i t i a l c o n t e x t como hacemos en el siguiente ejemplo:
j a v a -Djava.naminq. f a c t o r y .i r ~ i t i a l = c o m m s u r j~ ndi. . cosr~amir~q.CNCtxFactory -Djava.namir~g.provider.url=iiop://129.112.1. 9: 0 ReqisterIt

En el cliente
El cliente tiene la misma sentencia de importacibn y utiliza el contexto J N D I para obtener una referencia a1 objeto, en lugar de utilizar el registro. El mktodo J N D I l o o k u p ( ) devuelve un j a v a . l a n g . ~b j e c t , que debe ser entonces transmitido utilizando el m k t o d o n a r r o w ( ) de PortableRemoteObject.

import j ava. rmi. * ; import javax. rmi. PortableRemoteObject; i m p o r t javax.naming.1nitialContext; public class Helloclient
{

public static void main(String try {

args[] )

Cree el contexto J N D I y asdcielo a 61:


InitialContext ctx Object obj
= =

new Initialcontext

0;

//

Create the JNDI context

ctx. lookup ("/EgServert') ;

Asi se asocia el objeto a1 contexto JNDI igual que hizo el mktodo Naming. b i n d ( )
HelloInterface myobj
=

(HelloInterface) PortableRemoteObject .narrow(obj, Hel1oInterface.class);

String message = myobj . sayHello ( ) ; System.out .println ( m e s s a g e ); catch (Exception e ) [ System.out .println ("HelloClient exception:

"

e);

I
1
O t r a vez, las propiedades para el contexto JNDI (el nombre de factoria del contexto y URL proveedor) deben ser pasadas alas aplicaciones cliente en period0 de ejecucidn. Y, bisicamente, eso es todo.
Sun proporciona una guia detallada empaquetada con JDK sobre la conversidn de programas RMI

y applets existentes. T a m b i b se puede acceder a ella online en http:lljava.sun.comlj2se/l.3/docsl guidelrmi- iioplrmi-iiopgg. htrn I.
Observe que tambikn podemos escribir un servidor que se ajuste explicitamente a ambos clientes:
0 Exportindolo a ambos protocolos utilizando el mktodo e x p o r t o b j e c t ( ) . Obviamente, en este

caso n o necesitamos ampliar n i P o r t a b l e R e m o t e O b j e c t n i ~ n i c a s t ~ e m o t e ~ b j e c t .


0

Creando dos I n i t i a l c o n t e x t , uno para permitir la asociaci6n al registro RMI y uno para el servicio COSNaming, y asociando el servidor en ambos.

0 N o pasando el servicio de designaci6n como un argument0 de linea de comando utilizando la opcidn -D.

Por ejemplo, si quisikramos convertir a nuestro objeto Helloserver inicial en accesible sobre RMI (JRMP) y sobre RMI-IIOP, entonces se podria modificar como sigue:
import import import import public j ava . rmi. RemoteException; java. rmi .server.UnicastRemoteObject; java.uti1. Date; javax.rmi.PortableRemoteObject; class Helloserver implements HelloInterface

[
[

public void Helloserver() throws RemoteException PortableRemoteObject. exportobject ( t h i s ); / / ; // UnicastRemoteObject. exportobject ( t h i s )

Export for I I O P Export for JRMP

I
public String s a yHello ( ) throws RemoteException [ return "Hello World, the current system time is
"

+ new Date( ) ;

I
El objeto puede ser registrado con ambos contextos modificando nuestro archivo ~ e g i s t e~ r t :
import java.rmi.RMISecurityManager;

Procesamiento distribuido con RMI


import java.uti1.Prnperties; i m p o r t javax. naming. InitialContext; public class RegisterIt
{

public static void main (String [ 1 args) [ try{ if(Systern.getSecurityManager0 == null) Systern.setSecurityManager ( n e w ~ ~ I S e c u r i t y M a n a g e r ) ;O HelloServer obj
=

new HelloServer

0;

/ / Create the object

/ / Crear un JDNIContext para JRMP y asociar el objeto a1 registro / / Observe que estarnos utilizando el registro RMI via JNDI y no el / / registro por defecto. Properties p 1 = new Properties(); p l.put ("java.narning. factory. initial", "com. sun. j ndi. rrni. registry. RegistryContextFactory") ; InitialContext ctx 1 = n e w InitialContext ( ) ; ctx 1. rebind ("HellnServer", obj ) ; Systern.out .println ( "HelloServer bound in JRMP registry") ; / / Repita el rnismo paso para el registro IIOP Properties p 2 = new Properties( ) ; p 2.put ("java.narning. factory. initial", "corn. sun.jndi. c o s n a m i r ~ g . C N C t x F a c t o r y " ) ; InitialContext ctx 2 = new InitialCorltext ( p 2 ) ; ctx 2.rebind ("RernoteHelloServer", obj ) ; Systern.out.print1n ("HelloServer bound in IIOP registry"); catch(Exception e ) {]

Hemos abarcado muchos temas en esta section, asi que recapitulemos lo que acabamos de describir. Hemos hablado sobre 10s pasos a seguir en la escritura del servidor y del cliente RMI-IIOP, las diferencias entre ellos y c6mo el mismo objeto sewidor puede escribirse para ambos clientes RMI-JRMP y RMIIIOP. Sin embargo, lo que no hemos mencionado es corn0 un cliente CORBA puede solicitar sewicios de este objeto o como el cliente RMI-IIOP puede acceder a un objeto CORBA. Examinemos este punto. Una vez que tenemos una interfaz Java (estamos reutilizando el H e l l o I n t e r f a c e que escribimos antes), podemos utilizar el r m i c con la opci6n - i d 1 para generar su fuente IDL. ace. idl: Ennuestro c a s o , r m i c - i d 1 ~ello~nterfaceproduceelsiguientearchivo~ello~nterf
/**
HelloInterface. id1 Generated by rrnic -idl. Do not edit 2 0 August 2001 18:27:51 BST
/

#include #ifndef #define

"nrb. idl" HelloInterface HelloInterface


[

interface HelloInterface

: :CORBA: :WStringValue sayHello ( ) ;

#pragrna I D HelloInterface "RMI:HelloInterface:0000000000000000"

Este archivo .id1 puede ser utilizado por cualquier compilador IDL que se ajuste a CORBA 2.3 proporcionado por un vendedor, podemos generar un stub en nuestro lenguaje elegido (hablamos de C + + ya que es un lenguaje muy comun para objetos CORBA) para generar las clases de stub para ese lenguaje. El mismo compilador puede ser utilizado para generar clases skeleton/vinculo y 10s objetos de servidor C + + escritos para esas clases y se puede acceder a IDL con 10s clientes RMI-IIOP que hemos escrito.

RMI-IIOP y Java IDL


Java I D L es un Object Request Broker (ORB) proporcionado con JDK y que puede ser utilizado para definir, implementar y acceder a objetos CORBA desde Java. Java IDL cumple con la especificaci6n CORBA/IIOP 2.0 y el Mapping de O M G IDL para Java. La primera cuesti6n relacionada con este tema que se plantean la mayoria de 10s desarrolladores es: "ise estl eliminando RMI progresivamente a favor de RMI-IIOP?". La respuesta es un rotundo no. Otra pregunta que a veces se plantea a "ies RMI-IIOP un sustituto para Java IDL?". Una vez mls, la respuesta es no. U n cliente RMI-IIOP n o puede necesariamente acceder a un objeto CORBA existente. Si queremos utilizar Java para acceder a objetos CORBA que ya hemos escrito, Java IDL es nuestra mejor elecci6n. C o n Java IDL, que es t a m b i h una parte central de la plataforma Java 2, podemos acceder a cualquier objeto CORBA desde Java. La recomendaci6n general de uso para RMI-IIOP y Java IDL es Csta: "Si desea utilizar Java para acceder a recursos CORBA existentes, utilice Java IDL. Si, por el contrario, quiere que 10s recursos Java RMI sean accesibles a usuarios CORBA, entonces deberia utilizar RMI-IIOP. Si su aplicaci6n va a ser toda Java, entonces utilice RMI-IIOP". J2SEv1.3 incluye una nueva versi6n del idlj compilador de IDL a Java que toma u n archivo IDL y genera el servidor Java y las asociaciones d e cliente a partir de 61.

El archivo IDL
iRecuerda el IDL que acabamos de generar? Tomemos ese archivo (HelloInterfa c e . i d l ) como punto de partida para este ejemplo y veamos que podemos escribir objetos CORBA y utilizar Java IDL:
# i n c l u d e "orb. i d l " #ifndef #define HelloInterface HelloInterface

interface HelloInterface [ ::CORBA::WStringValue s a y H e l l o 0 ;

1;
#pragma I D HelloInterface #endif
"RMI:HelloInterface:0000000000000000"

Dos cosas pueden ocurrir con un archivo IDL. Podemos escribir el servidor o podemos escribir un cliente (como ya hemos mencionado antes en el ejemplo RMI-IIOP). Experimentaremos ambas en este ejemplo utilizando el compilador i d 1 j .

La implernentacion de servidor
Examinemos la secuencia de eventos asociados a la implementaci6n de servidor:

Procesamiento distribuido con RMI


0 Genere las asociaciones de lado servidor para el archivo IDL. Esto se realiza con el compilador i d 1 j :
idlj -i %JAVA-HOME%\lib -fserver HelloInterface.id1

Donde %JAVAPHONE% es el directorio de instalacion de J2SE 1.3. Inchimos el archivo o r b . i f 1con la opcion -i a1 compilador i d 1 j porque esti referenciado en el archivo I D L (recuerde que este I D L con el que empezamos fue autogenerado). La opci6n - s e r v e r indica a1 compilador que genere las asociaciones de lado servidor.
0

Escriba la implementaci6n. En terminologia CORBA, esto se denomina una clase sirviente.

El sirviente, H e l l o s i r v i e n t e , es la implementaci6n de la interfaz I D L y es una subclase de H e l l o I n t e r f a c e I m p l B a s e , que es generada por el compilador i d 1 j (para cada archivoxxx. i d 1 el compilador genera un archivo - x x x ~ m p l ~ a s .e j a v a ) . El sirviente contiene un metodo para cada operaci6n IDL. En este ejemplo, este es s61o el metodo s a y H e l l o ( ) . Observe que 10s metodos sirvientes son s61o metodos corrientes Java.
import java. util. Date;

public class HelloSirviente extends HelloInterfaceImplBase { public String sayHello( ) { returr, "Hello World, the current system time is " + new D a t e ( ) ;

0 Escriba la clase que asocia la implementaic6n (el sirviente) a1 servicio de designaci6n. Esta clase se

denomina el servidor en terminologia CORBA. Entonces, la clase H e l l o S e r v e r quedari como sigue:


i m p o r t o r g . omg. CosNaming. * ; i m p o r t org.omg. C o s N a m i r ~ g . N a m i r ~ g C o r ~ t e x t P a c k a* g;e . import org.omg.CORBA.*; public class HelloServer { public static void main(String try 1 args[]) {

/ / crear e inicializar el ORB ORB orb = ORB.init(args, null); / / crear el sirvientey conectarlo con el ORB HelloSirviente helloRef = new HelloSirviente orb. connect (helloRef);

( ) ;

/ / obtener el contexto d e designaci6i-I raiz org.omg. CORBA.Object obj Ref = orb.resolve initial references("NameService"); NamingContext ncRef = NamingContextHelper. narrow (objR e f ) ; / / Asociar la referencia d e sirviente a1 Contexto d e Designaci6n ""); NameComponent n c = new NameComponent("He11o". NameComponent path [ I = { nc) ; ncRef. rebind (path, helloRef) ; / / Esperar las invocaciones d e clientes java. lang.0bject sync = new java. lang.0bject ( synchronized (sync) { sync.wait ( ) ;

) ;

Capitulo 3
J

c a t c h IException e ) { S y s t e m . o u t . p r i n t l n ("Exceptior1:

"

e );

! !

I
Asi, queda claro en el c6digo anterior que el sewidor ejecuta las siguientes acciones:
O O O

Instancia el O R B Instancia el sirviente y lo conecta a1 O R B Obtiene una referencia de objeto CORBA para un contexto de designacion en el que registrar el Nuevo objeto C O R B A

O Asocia el nuevo objeto en el contexto de designacion con el nombre " H e l l o "


Espera las invocaciones del nuevo objeto

La implernentacion cliente
Sigamos ahora el procedimiento asociado a la implernentacion cliente. Necesitaremos crear una subcarpera cliente antes de ejecutar este paso:
O Genere las asociaciones de lado cliente para el archivo
idlj
-i

IDL:
HelloInterface.id1

%JAVA -H O M E % \ l i b - t d

client

-fclient

Escriba la clase cliente. ~ s t puede a ser un applet o una simple clase Java.
o r g . omg. C o s N a n l i n g . org.omg.CORBA.*;

import import

*;

public class HelloClient{ p u b l i c s t a t i c v o i d main I S t r i n g try{

args [ 1 ) {

//

c r e a r e i n i c i a l i z a r e l ORB targs, null); ORB o r b = O R B . i r ~ i (

/ / obterler e l contexto d e designaci6n r a i z


o r g . omg. CORBA.Object o b j R e f = o r b . r e s o l v e i n i t i a l r e f e r e n c e s ( " N a m e S c r v i c e " ); N a m i n g C o n t e x t n c R e f = N a m i r ~ g C o n t e x t H e l p e r .n a r r o w ( o b j R e f ) ; r e s o l v e r l a R e f e r e n c i a d e O b j e t o e r ~Designaci6n NameComponent n c = new NarneComponent ( " H e l l o " , " " ) ; NameCompor~ent p a t h [ 1 = { n c ) ; HelloInterface helloRef =

//

HelloInterfaceHelper.r~arrow(r~cRef.resolve(path) );
//
llamar a 1 o b j e t o s e r v i d o r Hello e imprimir S t r i n g h e l l o = helloRef .sayHello(); S y s t e m . o u t . p r i n t l n ( h e l l o ); catch (Exception e ) { System.out.println ("Exceptior~ : " + e ) ; resultados

Procesamiento distribuido con RMI


Finalmente, podemos ejecutar este ejemplo utilizando la siguiente secuencia:
1. Compilar todos 10s archivos java:
javac * . java

2. Crear 10s stubs para el servidor:


rrnic -iiop HelloServer

3. Ejecutar el servicio de Designaci6n t n a m e s e r v :


tnameserv -0RBInitialPort 900

4. Iniciar el servidor:
j ava -Dj ava. naming. f actory. initial=com. sun. jndi . c o s n a r n i n g . C N C t x F a c t o r y -Djava.r1arnir1g.provider.ur1=iiop://10ca1host:900 HelloServer

5. Eiecutar el c l i e n t e ~ e l l o ~ e r v e r :
java -Djava.narning. factory.initial=corn.sun.jndi .cosnarning.CNCtxFactory -Djava.r~arning.provider.url=iiop://localhost:900 Helloclient

C o n 10s dos ejemplos anteriores hemos visto c6mo escribir un objeto RMI-IIOP y c6mo hacerlo accesible a otros clientes CORBA. Tambikn hemos visto c6mo tomar un archivo IDL y generar un objeto CORBA y acceder a 61 con un cliente Java-IDL.

i d 1 j esta' sujeto tanto a1 modelo de herencia como a1 de delegaci6n. Esto significa que dada una interfaz X X en su archivo IDL, i d 1 j genera XXImplBa se.java. La implementacidn para X X que escribe debe ampliar la clase -XXImplBa s e . Esto se conoce como modelo de herencia. En ocasiones esto puede no resultar ritil si su implementacidn se amplia desde otra clase. (Recuerde que una clase Java puede implementar cualquier nrimero de interfaces pero s61o puede ampliar una clase.) En tal caso, puede indicar a1 compilador i d 1 j que utilice en modelo Tie. Si asi ocurre para la interfaz X X de su archivo IDL, i d 1 j generard XX- T i e - j a va y el constructor para X X T i e tomara' un XX como argumento. La implementacidn para XX que proporciona s61o es necesaria para implementar la interfaz XX. Para que esta implementacidn la utilice con el O R B , debe envolver su implementacidn en x x T i e . Por ejemplo:
XXImpl ohj = new XXImpl X X Tie tie = new XX Tie orb.connect ( t i e ) ;
-

(1; (ohj) ;

Como puede ver, el inconveniente de utilizar el modelo Tie es que aiiade un paso extra y una llamada de me'todo extra. El modelo de lado servidorpor defect0 del compilador i d 1 j es el modelo de herencia. Para utilizar el modelo de delegacidn:
idlj -fserverTIE Hello.id1

idlj

-fallTIE Hello.id1

RMI-IIOP y JZEE
M I - I I O P ofrece las siguientes ventajas para desarrolladores de programas con relaci6n a RMI-JRMP:
O Interoperatividad con objetos escritos en otros lenguajes via CORBA IDL independientes del

lenguaje

o Los contextos de transacci6n y seguridad pueden ser propagados implicitamente debido al uso de
IIOP, que puede propagar implicitamente informacion de context0

O Mantenimiento de cortafuegos de base I I O P via proxy I I O P que pueden pasar trifico I I O P de un mod0 controlado y manejable
C o n I I O P como protocolo de transporte, Java RMI encuentra el apoyo que necesita para fomentar el desarrollo de aplicaciones distribuidas de capacidad industrial, s61o en un entorno Java. N o obstante, M I - I I O P tiene algunos puntos dkbiles propios en comparaci6n con M I - J R M P : N o tiene asistencia de recoleccibn de residuos distribuidos. Las interfaces RMI D G C no representan 10s I D de objeto como lo hace CORBA, por lo que esas interfaces no son suficientes para CORBA/IIOP. N o puede confiar en las prestaciones de Java RMI/JRMP mientras utiliza MI-IIOP. El operador de conversi6n de clases no puede ser utilizado directamente en sus clientes despuks de obtener una referencia de objeto remoto. En su lugar, necesita utilizar un metodo especial para obtener el tip0 adecuado. N o le esti permitido heredar en mismo nombre de mktodo en su interfaz remota desde diferentes interfaces remotas base. Todas las definiciones constantes en interfaces remotas deben ser de tipos primitivos o Strings, y evaluadas en tiempo de compilaci6n. Entonces, ?quC idea esti detris de la intencidn de convertir M I - I I O P en el protocolo de facto en J2EE sustituyendo a RMI-JRMP?

Todos 10s contenedores J2EE son requeridos para mantener JRMP y RMI-IIOP y 10s contenedores t a m b i h deberian poder exponer todos 10s beans de empresa utilizando RMI-IIOP mediante las interfaces remotas de 10s beans.
Enterprise JavaBeans (EJB) es un constituyente clave de J2EE; 10s componentes de EJB residen dentro de 10s contenedores EJB, que proporcionan 10s entornos de period0 de ejecuci6n para 10s componentes. 1-0s contenedores ETB son desarrollados Dor diferentes vendedores tomando como base las especificaciones EJB (que utilizan la semintica RMI). Los vendedores son libres para elegir la implementaci6n para sus contenedores. Para promover la interoperatividad para 10s entornos EJB que inchyen sistemas procedentes de diferentes vendedores, Sun ha definido una representaci6n estindar de EJB a CORBA, basada en la especificaci6n de la asociaci6n Java en IDL desde OMG. Es decir, las interfaces EJB son intrinsecamente interfaces RMI-IIOP.
Puede acceder a la representacidn EJB en CORBA en http:lljava.sun.comlproductslejblindex.html.

Procesamiento distribuido con RMI


Como veremos en este libro, EJB presenta un modelo de creaci6n de aplicaciones de empresa distribuidas que pueden ser desplegadas en un entorno heterogheo. RMI estindar con JRMP falla en algunos aspectos:
0

Es la unica solucion de Java y EJB tambiCn deberia ser accesible para otros clientes en una entorno de empresa hecho, no obedece a la propagacion de context0 en absoluto)

0 N o obedece a la propagation de contextos de transaction y seguridad en las JVM distribuidas (de

o N o es tan reajustable como I I O P


RMI-IIOP supera estas limitaciones de RMI-IIOP. La representacion de CORBA en EJB no solo permite la interoperatividad entre irnplementaciones de multiples vendedores del contenedor EJB, sino que tarnbikn capacita a clientes no Java para que accedan a aplicaciones de lado servidor como EJB a traves de 10s API CORBA estindar. La especificacion EJB 2.0 permite la operatividad entre contenedores utilizando RMI-IIOP.

Ajustar aplicaciones RMI


El API de RMI ofrece rnuchas propiedades de sistema que puede ser ejecutadas dinimicarnente en el period0 de ejecucion con la opcion -D en la JVM. (Por ejemplo, j ava -D j ava. rmi .dgc . leaseValue=3OOOO ~ y ~ p p Son ) . muy 6 d e s para ajustar el rendimiento y depurar las aplicaciones. Estas propiedades estin catalogadas en las siguientes tablas, empezando con un resumen de todas las propiedades que pueden ser configuradas en las JVM cliente y servidor: Propiedad Introducida primera vez (versi6n) Descripci6n

j ava .rmi .dgc .leasevalue

La duration del alquiler concedido por el D G C a 10s clientes que acceden a objetos remotos en esta JVM. Los clientes normalmente renuevan un alquiler cuando ha expirado en su 50%, por lo que un valor muy corto aumentara el traf~co en la red y arriesgara renovaciones tardias a cambio de demora en llamadas a U n r e f e r e n c e d . unref erenced.Elvalorpor defectoes 600000 milisegundos (10 minutos). Las osiciones desde las que las clases ubgcadas par esta JVMpueden ser descargadas. R e d e ser un URL o unallsta d e ~ ~ ~ s e ~ a r a d a ~ espacio (para 1.2) y puede ser configurada tanto en JVM cliente como en JVM serv~dor. El nombre de host que debe estar asociado a stubs remotos para objetos remotos creados localmente, ara permitir a 10s clientes invocar mktodos enefob'eto remoto. EIvalor or defect0 se esta propiedad es la direction IP defhost local.
1.1

java.rmi.server .codebase

java.rmi.server .hos tname

java.rmi.server logcalls

Llamadas entrantes de metodo y excepciones serin registradas e n s y s tem. err siestees true.

La tabla continua en la pagina siguiente

185

--

Propiedad

Introducida primera vez (version)


1.1.8

Description

java. rmi. server .randomIDs

Si este valor es true, 10s identificadores de objeto para objetos remotos exportados por esta JVM serin generados utilizando un generador criptogrifico seguro de numeros aleatorios. El valor por defecto es false. Si este valor es true, la JVM no puede cargar automiticamante desde otro lugar que no sea su classpath local y desde la propiedad j a y a . r m i . s e r v e r . codebasedel servidor. Esta p u e d e c o n f i g u r a r s e e n la J V M cliente y servidor.

java. rmi. server .use LocalHostName

1.1.7

RMI utiliza ahora una direccibn I P para identificar el host local cuando la propiedad j a v a . r m i . s e r v e r . h o s t n a m e no e s t i especificada no sepuede obtener un nombre de dominio caEficado para el host local. Si re configura en true, RMI estiobligado autilizar el nombre de dominio calificado por defecto. Si este valor es true, el tunelado HTTP es desactivada, incluso cuando se confi ura http. proxyHost.El valor por efecto es ahe y esta propiedad es util para JVM cliente.

La siguiente tabla describe las propiedades especificas de activacibn:

1-

Propiedad

Introducida primera vez (version)

Descripcidn

El valor de esta propiedad representa el puerto T C P en el que el demonio de sistemadeactivacibn, rmid, escuchari las llamadas remotas entrantes. El valor por defecto es 1098.
java. rmi .activation .activator.class 1.2

La clase que implementa la interfaz iava.rmi.Activation.Activator. Esta ' ropicdad es utilizadainternamente para focalizar la impkmmtacibn residente del activador desde el que uede encontrarse el nombre de clase s u t! .

Esta tabla final representa un resumen de propiedades que son especificas de la implementacibn JDK SUN de RMI:

Procesamiento distribuido con RMI


Propiedad Introducida primera vez (versi6n) Descripcidn

s u r ~ r. m i . a c t i v a t i o n .?x?cTirneout s u r ~ r.r n i . a c t i v a t i o n .sr~apshotInterval

sun. r m i . 1oq.debuq s u n . rrni . r m i d .m a x s t a r t q r o ~ l p

.a c t i v a t i o n .debugExec

s u n . rrni. s e r v e r

s u r ~ r. m i . d g c checkInterva1

1.1

s u n . rrni . d g i : . l . ~ q L e v e l

1.1

s u n . rrni . d g z . s e r v e r .g c I n t e r v a 1

1.2

El tiempo que rimd esperari para que un grupo de activacidn generado arranque. El valor por defecto es de 30,000 milisegundos. El ndmero de actualizaciones por las que esperarien sistema de activacidn antes de que serialice una instantinea de su estado a1 archivo de registro rmid del disco. Una "actualizacidn" hace referencia a un cambio persistente en el estado de sistema de activacidn (por ejemplo, el registro de un objeto activable) desde que fue tomada la dltima instantinea. Cambiar el valor de esta propiedad puede utilizarse para hacer que rmid se reinicie mis ripidamente (tomando instantineas del registro con mis frecuencia) o conseguir que rimd sea eficiente (tomando instantineas del registro con menor frecuencia). El valor por defecto es 200. Si este valor es true, 10s detalles de la actividad de registro de rmid son enviados a System.err. El miximo numero de JVM de grupo de activacidn que rmid permitiri simultineamente en el estado de "generaci6n pero todavia inactivo". Si necesitamos iniciar mis JVM, 6stas estarin en cola hasta que uno de 10s intentos actuales de generacidn sea efectivo o caduque. Esta propiedad no limita el numero miximo de VMs activas; e s t i destinada a suavizar picos imprevistos de actividad para evitar alcanzar limites del sistema operativo. Fijar el valor de esta propiedad en un ndmero menor puede resultar en un mayor tiempo dearranque de rmid fijarelvaloraun ndmero mayor puede reducir el tiempo de arranque; fijar este valor demasiado alto puede hacer fallar el rmid porque su sistema puede quedarse sin recursos. El valor por defecto es 3. S; estevalores true, el sistemade activacidn imprimiri informaci6n de depuracidn a la linea de comando que se utiliza para grupos de activacidnde generacidn. Pordefecto, el valores false, por lo que lainformaci6n de depuracidn n o se imprime. La frecuencia con la que el periodo de ejecucidn de RMI comprueba 10s alquileres D G C que ha expirado. El valor por defecto es 300,000 milisegundos. Controla el registro de llamadas entrantes y salientes relacionadas c o n la c o n c e s i 6 n , renovacion y expiracidn de alquileres. Cuando es necesario certificar que 10s objetos remotos inalcanzables n o son exportados y son recogidos p o r el recolector de residuos o p o r tunamente, el valor de esta propiedad representa el interval0 m i x i m o que p e r m i t i r i el periodo de ejecucidn entre recolecciones de residuos en el curnulo local. El valor p o r defecto es 60,000 milisegundos.

tabla continua

Capitulo 3
Propiedad Introducida primera vez (versidn) Descripcidn

s u n . mi . s e r v e r .? x c e p t i o n T r a c e

s u n . rrni. t r a n s p ~ r t .logLevel sun. rmi. t r a n s p o r t .tcp. localH?st NameTimeOut sun. rmi. t r a n s p o r t .tcp.loqLevel slli-1. r m l . t ~ a n s p o r t .tcp.readTirneout

s u r i . r m i .d g c .c l e a n I n t e r v a 1

sun. r m i .dgc. c l i e n t .g c I n t e r v a 1

sun. rmi. loader . 1ogLex.e 1

s u n . rmi .s e r v e r .l.igL?vel

Controla el registro de cada nombre de clase y base de cddigo, siempre que el periodo de ejecucidn RMI intenta cargar una clase c o m o resultado d e unmarshaling un argument0 o un valor devuelto. La base de cddigo impresa es la base de cddigo anotada, per0 puede que no sea necesariamente la verdadera base de cddigo desde la que se carga la clase; el cargador de clase RMI difiere la carga de clase a1 cargador de clase de contexto de hilo, que puede que cargue la clase desde el classpath, . v , no desde la base de cddino anotada. Controla la salida de sefiales de pila de lado servidor procedentes de excepciones y errores lanzados por llamadas remotas entrantes lanzadas. Si este valor es t r u e , las seiiales d e pilas d e excepcidn s e r i n imprimidas. Por defecto (false), las seiiales de pilas de excepciones y errores n o son imprimidas. Controla el registro detallado a travks de la capa de transporte. Representa el tiempo que el periodo de ejecucidn RMI esperar6 para obtener un nombre de dominio calificado para el host local. El valor por defecto es 10,000 milisegundos. Controla el registro detallado para la subcapa de transporte especifica de T C P . Representa el tiempo invertido como tiempo limite de inactividad para conexiones RMI-TCP entrantes. El valor es pasado a Socket. setSoTimeout. Esta propiedad se utiliza s61o en casos en 10s que un cliente no ha suprimido una conexion sin usar como deberia. El valor por defecto es 7,200,000 rnilisegundos (2 horas). Representa el tiernpo miximo que el periodo de ejecucidn RMI esperari antes de reintentar una llamada D G C "limpia" fallida. El valor por defecto es 180,000 milisegundos. Cuando es necesario asegurar que las IlarnadasDGC limpias para referencias remotas inalcanzables son efectuadas oportunarnente, el valor de estapropiedad representa el interval0 miximo que el periodo de ejecucidn R M I permitir6 entre recolecciones d e residuos del cdmulo local. El valor por defecto es 60,000 milisegundos. Controla el registro de cada nombre de clase y base de cddigo, siempre que el periodo de ejecucidn RMI intenta cargar una clase c o m o resultados de lectura de un argument0 o un valor devuelto. La base de cddigo impresa es la base de c6digo anotada per0 puede que no sea necesariarnente la base de c6digo desde la que la clase se carga; el cargador de clase RMI difiere la carga de clase a1 actual cargador de clase de contexto del thread, que puede cargar la clase desde la ruta de clase, y n o desde la base de cddigo marcada. Controla el registro de informacidn relacionada con llarnadas salientes, incluido alguna informacion de reutilizacidn de conexiones.

Procesamiento distribuido con RMI


Propiedad Introducida primera vez (versi6n)
1.1.6

Descripcidn

s u n . rrni. t r a n s p o r t .connectlonTimeout

sun. rmi. transport .prosy.connectTimeout

1.1

s u n . rrni. t r a n s p o r t .proxy. logLevel

1.1

R e p r e s e n t a el p e r i o d 0 d u r a n t e el q u e las conexiones de socket RMI pueden residir en estado "sin usar", antes de que el periodo de ejecucidn RMI permita que se liberen (cierren) esas conexiones. El valor por defecto es 15,000 milisegundos. Representa el miximo tiempo qie el periodo de ejecucidn RMI esperari para que se complete un intento de conexidn (createsocket), antes de intentar contactar con el servidor a traves de HTTP. Esta propiedad s61o se utiliza c u a n d o la propiedad h t t p . p r o x y H o s t e s t i c o n f i p r a d a y el valor de java.rmi.server.disableHttp es false. El valor por defecto es 15,000 milisegundos. Controla el registro de eventos (createsocket y createserversocket) cuando la clase p o r defect0 RMISocketFactory es utilizada. Este tip0 de registro puede ser dtil para aplicaciones que utilizan RMI sobre HTTP. Los eventos en factorias de socket de adaptacidn n o son registrados en esta propiedad.

Las propiedades RMI de Sun descritas son utiles para depurar per0 es importante recordar que no son sostenidas oficialmente y que estin sujetas a cambios constantes. Las propiedades que terminan en " .logLevelWtiene salida redirigida a s ystem. err conposibles valores de "SILENT", "BRIEF" y "VERBOSE".

Resumen
Hemos abarcado mucho terreno en este capitulo, desde la arquitectura bisica RMI hasta el tunelado H n P . Si se siente un poco abrumado por tanta informaci6n, t6meselo con calma. Repase 10s ejemplos y escriba algunas aplicaciones de prueba; eso le hari avanzar. En el capitulo, hemos tratado:
O La arquitectura RMI.
U Desarrollo de aplicaciones RMI. Las etapas necesarias para la creaci6n de aplicaciones efectivas.

o Pasada de parimetros en RMI, 10s tipos disponibles y su uso. o Activacion de objetos, 10s beneficios de ejecucidn basados en la necesidad.
0 RMI, cortafuegos y HTTP. Los diferentes mitodos disefiados para permitir el acceso del trifico JRMP a travis de cortafuegos. 0 El desarrollo de RMI sobre I I O P y la integraci6n de RMI sobre CORBA.

Recuerde que, aunque RMI-IIOP es el modelo para J2EE, JRMP esti todavia muy activo. Si su aplicaci6n requiere Gnicamente comunicaci6n Java-Java, entonces RMI-JRMP es una soluci6n viable. La inclusi6n de RMI-IIOP en el nucleo de JDK (desde la versi6n 1.3 de J2SE) y su intima asociaci6n con EJB, lo establece como una tecnologia de base para el software intermediario de empresa. En perspectiva, RMI ha realizado un largo recorrido desde sus primeros dias, cuando no existia ning6n modelo distribuido en Java. En la actualidad, es el nude0 del modelo distribuido de Java en J2EE y constituye la base para futuras tecnologias, como JINI, que estin transformando el mod0 en el que dispositivos y sistemas serin redificados conjuntamente. Aunque esti fuera del alcance de este capitulo, Jini esencialmente revoluciona de forma espectacular el modelo y la arquitectura RMI. El capitulo cuarto aborda el acceso alas bases de datos utilizando el API Java Database Connectivity (JDBC).

Programacion de bases de datos con JDBC


Una base de datos relacional es normalmente el recurso primario de datos en una aplicaci6n de empresa. El API JDBC ofrece a 10s desarrolladores de programas un mod0 de conectar con datos relacionales desde el interior del c6digo Java. Utilizando el API JDBC, 10s desarrolladores pueden crear un cliente (que puede ser cualquier cosa, desde un applet a un EJB) que pueda conectar con una base de datos, ejecutar instrucciones de Structured Query Language (SQL) y que procese el resultado de esas instrucciones. Si esti familiarizado con SQL y las bases de datos relacionales, la estructura del API JDBC es ficil de entender y utilizar. El API proporciona conectividad y acceso a datos en toda la extensi6n de bases de datos relaciones. Puede conseguir este objetivo porque ofrece una serie de mktodos genkricos de acceso a bases de datos para bases de datos relacionales que se ajusten a SQL. JDBC generaliza las funciones de de vendedor de una determinada acceso a bases de datos mis comunes abstravendo 10s detalles es~ecificos base de datos. El resultado es un conjunto de clases e interfaces, localizadas en el paquete-j ava sql,que pueden ser utilizadas con cualquier base de datos que tenga un driver JDBC apropiado. Este permite que la conectividad JDBC sea suministrada de forma constante para cualquier base de datos. Tambikn significa que, asegurindose de que la aplicaci6n se ajusta alas caracteristicas de las bases de datos disponibles mis comunes, una aplicaci6n puede utilizarse con una base de datos diferente cambiando simplemente a un driver JDBC diferente.

Sin embargo, hay mucha mis en conectividad de bases de datos en un entorno de empresa que una simple conexi6n de bases de datos y ejecuci6n de instrucciones. Hay aspectos adicionales que deben ser resueltos incluido el uso de reserva de conexiones para optimizar 10s recursos de la red y la implementacidn de transacciones distribuidas. Aunque algunos de 10s conceptos que se encuentran detris de estos aspectos son avanzados, veremos que enfrentarse a ellos no es en si demasiado complejo. Estudiaremos el API JDBC 3.0 que, en el momento de publicaci6n de este libro, es la d t i m a versi6n de API JDBC. La versi6n 2.0 del API JDBC tiene dos partes: JDBC 2.1 Core API y JDBC 2.0 Optional

Capitulo 4
Package API, y aunque estos dos API han sido combinados en la versi6n 3.0, las clases e interfaces JDBC siguen encontrindose en dos paquetes Java: j a v a sql, y j a v a x sql.

java.sq1 Este paquete contiene clases e interfaces disetiadas teniendo en mente la arquitectura tradicional cliente-servidor. Su funcionalidad se centra primordialmente en servicios de programaci6n bisicos de bases de datos, como creaci6n de conexiones, ejecucion de instrucciones e instrucciones preparadas, y consultas por lotes (batch). Funciones avanzadas tales como actualizaci6n de lotes, listas de resultados desplazables, aislamiento de transacciones y tipos de datos S Q L tambitn estin disponibles. javax.sq1 Este paquete introduce algunos cambios importantes de arquitectura en la programacion JDBC en comparacion con javasql y ofrece mejores transacciones para la gestion de conexiones, transacciones distribuidas y conectividad de legado. Este paquete tambitn introduce reserva de conexiones dirigidas por contenedor, transacciones distribuidas y filas.

N o intentaremos cubrir conceptos generales de programaci6n de bases de datos en este capitulo; se requieren conocimientos bisicos previos sobre S Q L y sobre el desarrollo de aplicaciones clienteservidor. U n finico capitulo n o es suficiente para abarcar la programaci6n de bases de datos de forma exhaustiva por lo que adoptaremos un enfoque de alto nivel para el API JDBC. En lugar de intentar analizar, construir y analizar grandes aplicaciones, estudiaremos pequefios fragmentos de codigo que ilustren el uso de varias clases e interfaces de j a v a . s q l y j a v a x . sql. En concreto, examinaremos 10s siguientes puntos:
0

Conectividad de bases de datos utilizando drivers JDBC

O C o m o pueden realizarse varias operaciones S Q L utilizando el A P I JDBC estindar incluido obtener conexiones de bases de datos, enviar instrucciones S Q L a una base de datos y recuperar
resultados de consultas debases de datos
0

C 6 m o representar tipos S Q L en Java Caracteristicas avanzadas del API JDBC, incluido listas de resultados desplazables y actualizaciones de lotes Nuevas caracteristicas del API JDBC 3.0, incluidos puntos de salvaguardia

Entonces continuaremos para considerar temas de macro-nivel que incluyen:

O Utilizar el paquete javaxsql y J N D I para obtener conexiones de bases de datos


0

Reserva de conexiones, incluido un anilisis sobre reserva tradicional de conexiones versus reserva de conexiones basada en fuentes de datos habilita las transacciones distribuidas)

O Transacciones distribuidas (c6mo el paquete j a v a x . sql, junto con el API Java Transaction,

n Los conceptos bisicos de una fila y c6mo proporcionan un alto nivel de abstracci6n para el acceso
a bases de datos y la ficil serializaci6n de datos N o s centraremos principalmente en el paquete javasql, ademis de en la creaci6n de conexiones de bases de datos y el control programitico de transacciones. Empezaremos comprendiendo c 6 m o las aplicaciones Java pueden conectar y comunicarse con bases de datos.

Programacion de bases de datos con JDBC

Es importante comprender que JDBC abstrae la conectividad de bases de datos de las aplicaciones Java. U n vendedor de bases de datos proporciona normalmente un conjunto de APIs para acceder a 10s datos gestionados por el servidor de base de datos. Los vendedores de bases de datos populares como Oracle, Sybase, e InFormix ofrecen APIs de propiedad para el acceso de cliente. Las aplicaciones de cliente escritas en lenguajes nativos como C / C + puede utilizar estos APIs para obtener acceso directo a 10s datos. El API JDBC ofrece una alternativa a1 uso de estos APIs especificos del vendedor. Aunque este elimina la necesidad de que el desarrollador de Java acceda a APIs nativos especificos de vendedor, la capa JDBC puede todavia necesitar en dltima instancia realizar estas llamadas nativas. U n driver JDBC es una capa de software intermediario que traduce las llamadas JDBC a 10s APIs especificos del vendedor.

Dependiendo de si se esti utilizando el paquete j ava .sql o el paquete j avax .sql,existen diferentes enfoques para conectarse a una base de datos a travks del driver. Con independencia de esto, para acceder a datos necesitari un driver de base de datos, probablemente suministrado por el vendedor de base de datos o por un proveedor del servidor JZEE. U n driver no es mis que una implementaci6n de varias interfaces especificadas enlos paquetes j ava .sql y j avax .sql. Hay cuatro enfoques diferentes para conectar una aplicaci6n a un servidor de base de datos a travks de un driver de base de datos. La siguiente clasificaci6n es una norma de industria y 10s productos comerciales de driver estin clasificados segdn esta norma.

Tipo 1 Puente JDBC-ODBC


O p e n Database Connectivity (ODBC) fue creado originalmente para proporcionar un API estindar para SQL en las plataformas Microsoft Windows, y fue mis tarde perfeccionado para proporcionar SDK a otras plataformas. O D B C esti basado, en parte, en la especificaci6n X/Open Call-Level Interface (CLI), que es un API estindar para el acceso a bases de datos. Este API proporciona asociaciones en 10s lenguajes C y Cobol para el acceso a bases de datos. CLI esti pretende ser neutral en cuanto a plataformas y bases de datos, ahi donde diverge O D B C de la especificaci6n. SQL integrado fue uno de 10s enfoques barajados para el acceso a bases de datos por SQL Access Group. Esto suponia integrar instrucciones SQL en aplicaciones programadas en lenguajes de alto nivel y preprocesarlas para generar llamadas de funci6n nativa. O D B C define un conjunto de funciones para acceso directo a datos, sin la necesidad de integrar SQL en aplicaciones cliente. La primera categoria de drivers JDBC proporciona un puente entre el API JDBC y el API ODBC. El puente traduce las llamadas JDBC estindar a llamadas O D B C correspondientes y las envia a la fuente de datos O D B C a travks de librerias ODBC:

Capitulo 4

1
1

Apl1cac16n Java

Fuente de
datOs

1
i

Puente JDBC-ODBC

'
4

'

'

AF?
+

ODBC

--

1,

Capa ODBc

Los limites de proceso estin marcados por una linea discontinua. El Puente JDBC-ODBC traduce las llamadas de API JDBC en llamadas equivalentes ODBC. El driver delega entonces estas llamadas en la fuente de datos. Las clases Java para el API JDBC y el Puente JDBC-ODBC son invocadas en el proceso de aplicaci6n del cliente; la capa O D B C se ejecuta en otro proceso. Esta configuracibn requiere que cada cliente que ejecute la aplicaci6n tenga el API Puente JDBC-ODBC, el driver O D B C y el API de lenguaje de nivel nativo, como la libreria O C I para Oracle, instalado. Esta soluci6n para el acceso a datos no es eficiente para requisitos de acceso a bases de datos de alto rendimiento debido a las mdltiples capas de desreferencia para cada llamada de acceso a bases de datos. Ademis esta soluci6n limita la funcionalidad del API JDBC a favor de la funcionalidad del driver ODBC. El uso de JDBC-ODBC debe ser considerado dnicamente para prop6sitos experimentales. J2SE incluye clases para el Puente JDBC-ODBC y por el10 no es necesario instalar ningdn paquete adicional para utilizarlo. Sin embargo, si tiene que configurar el gestor de O D B C creando nornbres de fuente de datos, data source names (DNS). Los DNS son simplemente configuraciones nornbradas que vinculan una base de datos, un driver apropiado y algunas configuraciones adicionales. El puente JDBCO D B C debe funcionar con la mayoria de 10s drivers O D B C 2.0.

Tipo 2

- Parte Java, parte driver nativo

Los drivers Tipo 2 utilizan una combinaci6n de implementaci6n Java y API nativos especificos de vendedor para proporcionar acceso a datos. Hay una capa menos que atravesar que en el driver Tipo 1 por lo que, en general, un driver Tipo 2 seri mis ripido que un driver Tipo 1:

Programacion de bases de datos con JDBC

I
I

datos

7 --

I
I
I

'

API JDBC

;Drlver JDBC (delwdedor


I

API
'
-

v
\

especlflco

I I I I

Las llarnadas de bases de datos JDBC son traducidas en llarnadas API especificas del vendedor. La base de datos procesari la solicitud y enviari de vuelta 10s resultados a travks del API, que a su vez la enviari de vuelta a1 driver JDBC. El driver JDBC traduciri 10s resultados a la norrna JDBC y 10s devolved a la aplicaci6n Java. Igual que 10s drivers Tipo 1, la parte Java, el driver de c6digo parte nativa y el API de lenguaje nativo especifico delvendedor deben estar instalados en cada cliente que ejecute la aplicaci6n Java. Corno el cbdigo nativo utiliza protocolos especificos de vendedor para cornunicar con la base de datos de forrna eficiente, 10s drivers Tipo 2 son rnis eficientes que 10s drivers Tipol. Adernb, ahora tenernos uso pleno del API del vendedor. Estos dos factores significan que 10s drivers Tipo 2 son, en general, preferidos a 10s drivers Tipo 1.

Tipo 3 Servidor intermediario de acceso a bases de datos


Los drivers Tipo 3 utilizan un sewidor interrnediario (software interrnediario) de base de datos que tiene la capacidad de conectar rnliltiples clientes Java a rnliltiples sewidores de base de datos:

I
I

Aplicacldn Java

Capitulo 4
Los clientes conectan a 10s servidores de base de datos rnediante un cornponente servidor interrnediario (corno un escuchador) que actua corno una puerta para multiples servidores de bases de datos. La aplicacion cliente Java envia una llarnada JDBC a travks de un driver JDBC a1 servidor interrnediario de acceso a datos, que cornpleta la solicitud a la Fuente de Datos utilizando otro driver (por ejernplo, un driver Tipo 2). El protocolo utilizado para cornunicar entre clientes y el servidor interrnediario depende del vendedor del servidor de software interrnediario pero el servidor interrnediario puede utilizar diferentes protocolos nativos para conectar con diferentes bases de datos. BEA WebLogic incluye un driver Tipo 3. U n o de las ventajas de utilizar un driver Tipo 3 es que concede flexibilidad a la arquitectura de la aplicacion, ya que el servidor interrnediario puede abstraer detalles de conexiones a servidores de bases de datos.

Tipo 4

- Drivers Java puro


Apl~cacion Java

Los drivers Tipo 4 son una alternativa Java puro a 10s drivers Tipo 2:

1
Drwer JDBC

JDBC

Los drivers Tipo 4 convierten las llarnadas de API JDBC en llarnadas de red directas utilizando protocolos de red especificos del vendedor. Lo realizan estableciendo conexiones de socket directas con la base de datos. Los driver Tipo 4 ofrecen generalrnente rnejor rendirniento que 10s drivers Tipo 2 y Tipo 2. Los drivers Tipo 4 son tarnbikn 10s drivers rnis ficiles de desplegar ya que n o hay librerias adicionales ni software interrnediario que instalar. Todos 10s principales vendedores de bases de datos proporcionan drivers JDBC Tipo 4 para sus bases de datos y tarnbikn estin disponibles en vendedores de terceros. Puede encontrar una lista de drivers JDBC, de 10s cuatro tipos, en http://industry.java.sun.com/products/ jdbcldriverd. En el mornento de escribir este libro, hay rnis de 160 drivers disponibles.

Como comenzar
Para ernpezar a utilizar JDBC con nuestras aplicaciones, necesitarnos instalar un driver. Obviarnente, tarnbikn necesitamos un servidor de base de datos. Para mayor sirnplicidad, en este capitulo, utilizarernos la

Programacibn de bases de datos con JDBC


base de datos Cloudscape para demostrar que el API JDBC, como servidor de Implementacidn de Referencia J2EE de Sun, incluye una versi6n de Cloudscape. Cloudscape esti escrito utilizando Java y ~2~~~~0~~%\lib\~loudscape\~lo ja urd .scape. puedeencontrarloen% Tambikn puede obtener una copia de evaluaci6n de Cloudscape en http://www.cloudscape.com. Para utilizar el API JDBC y la base de datos Cloudscape, afiada el archivo c l o u d s c a p e j a r a su CLASS PATH.Consulte la documentaci6n de Cloudscape para instrucciones sobre cdmo utilizar Cloudview, una interfaz grifica de usuario (GUI) para acceder a la base de datos Cloudscape.

Cloudscape es un sistema de gestidn de base de datos de pequefio contorno construido en Java y que puede ser utilizado de modo integrado o cliente-:emidor. Cuando es utilizado de modo integrado, Cloudscape se ejecuta dentro del proceso de aplicacidn. Este es el modo mis sencillo para la gestidn de base de datos puesto que, aparte de incluir las clases Cloudscape en su CLASSPATH, no supone ninguna configuracidn. El mod0 cliente-servidor le permite acceder a Cloudscape en la forma tradicional cliente-servidor. Como Cloudscape es implementado en Java, no se requieren drivers adicionales de bases de datos ya que 1as llamadas JDBC son representadas en llamadas API Java Cloudscape dentro del mismo proceso. En el modo cliente-senidor, estas llamadas son representadas en llamadas RMI en el proceso del servidor Cloudscape.
Si desea crear otra base de datos, asegairese de que sigue las instrucciones para configurar la base de datos dadas por el vendedor de la base de datos e instale un driver de base de datos adecuado.

El paquete java.sql
Las clases del paquete j a v a s q l pueden dividirse en 10s siguientes grupos basados en su funcionalidad: Gestidn de conexidn Acceso a bases de datos Tipos de datos Metadatos debase de datos Excepciones y advertencias Examinemos las clases disponibles en cada grupo.

Gestion de conexion
Las siguientes clases/interfaces le permiten establecer una conexidn a la base de datos. En la mayoria de casos. conlleva una conexidn a la red: Clase java.sql.DriverManager Descripci6n Esta clase proporciona la funcionalidad necesaria para gestionar uno o mis drivers debase de datos. Cada driver a suvezle permite conectar con una base de datos especifica. ~ s t es a una interfaz que abstrae el protocolo de conexi6n especifico del vendedor. Puede e n c o n t r a r implementaciones de estainterfazenvendedores de bases
La tabla continua en la prigina siguiente

197

Programacion de bases de datos con JDBC


Clase
java.sql.Array

Descripcion Esta interfaz proporciona una abstracci6n ARRAY de lenguaje Java, una coleccion de tipos de datos SQL. Esta interfaz proporciona una abstraccion de lenguaje Java de SQL tipo BLOB. Esta interfaz proporciona una abstraccion de lenguaje Java de SQL tipo CLOB. Esta clase proporciona una abstraccion de lenguaje Java de S Q L tipo D A T E . Aunque j a v a . u t i l . D a t e proporciona una representation de fecha de pro 6sito general, la clase j ava . s q l .D a t e es preferib& para representar datos en aplicaciones centradas en bases de datos, ya ue este tip0 re resenta directamente en ti o S~LDA?E.~ b s e x - v e ~ u e ~ c ~ ava a s. esql j .Dat eam&a laclasej ava. util. Date. Esta clase porpociona una abstraccion de lenguaje Java d e S Q L t i p o ~ ~ ~ ~ y a m p l i a l a cava. l a s e util j .Date. Esta clase porpociona una abstraccion de lenguaje Java de SQLtipo~lME,yamplialaclase j ava .util .Date. Esta clase proporciona una abstraccion de lenguaje Java de S Q L tip0 REF. Esta interfaz proporciona una abstraccion de lenguaje Java de tipos estructurados SQL. Esta clase alberga un conjunto de numero enteros, cada uno de ellos se corresponde con un tip0 SQL.

j ava. sql. Blob j ava .sql .Clob j ava. sql. Date

java.sql.Time java.sql.Timestamp java.sql.Ref java.sql.Struct

j ava. sql .Types

Como veremos m6s adelante, a d e m b de las anteriores, el API JDBC tambien especifica representaciones estindar entre tipos primitivos en Java y en SQL. El API JDBC tambien incluye recursos para tratar tipos de bases de datos adaptadas. Estos tipos pueden ser representados como objetos j ava .s q l .SQLData y se puede acceder a 10s datos contenidos en estos tipos utilizando las interfaces j ava .s q l .SQLInput y j ava .s q l .SQLOutput que proporcionan una interfaz tip0 corriente (stream) para acceder a 10s datos.

Metadatos de base de datos


El API JDBC tambien incluye recursos para obtener metadatos sobre la base de datos, pardmetros para las instrucciones y resultados: Clase
java.sq1.DatabaseMetadata

Descripci6n Puede encontrar informaci6n sobre las caracteristicas de bases de datos utilizando estainterfaz. Puede obteneruna instancia de esta interfaz utilizando j a v a . s q l .
Connection.
La tabla continua en la pigina siguiente

Capitulo 4
Clase
java.sql.Resu1tSetMetaData

Descripci6n Esta inetrfaz propociona mktodos para acceder a metadatos del Resul tse t,como 10s nombres de las columnas, sus tipos, el nombre de tabla correspondlente y otras propiedades. Esta interfaz le permite acceder a 10s tipos de parimetros de bases de datos en instrucciones preparadas.

java.sql.ParameterMetadata

Excepciones y advertencias
Las siguientes clases encapsulan errores de acceso a bases de datos y advertencias: Clase Descripci6n Esta excepci6n representa todas las condiciones de excepci6n relacionadas con JDBC. Esta excepci6n tambkn incorpora todas las excepciones relacionadas con el driver/base de datos y c6digos de error. Esta excepci6n representa las advertencies de acceso a base de datos. En lugar de tener que capturar esta excepcibn, puede utilizar 10s mCtodos apropiados en

y java .sql .~ e s u t l ~ e paraaccederalas t advertencias.


j ava .sql .BatchUpdateException

java.sql.Connection, java.sql.Statement,

~ s t e e s u n a c a s o e s ~ e c i a l dava. e j sql .SQLException destinada a actiallzaciones de lotes. Estudiaremos las actualizaciones de lotes mis adelante en este capitulo.

~ s t es e un caso especial de j ava. sql .SQLWarning destinado a errores de truncamiento de datos. Observe ue 10s ti os de datos no siempre coinciden entre Java y Q Q ~y , e transferencia de datos puede suponer truncamiento de datos. Ademis de estos rasgos, JDBC tambikn proporciona recursos para registros y permisos de seguridad asociada para registros. En las siguientes secciones, estudiaremos algunas de las clases e interfaces mis utilizadas de este API. En particular, aprenderemos: C6mo cargar un driver de base de datos

O C 6 m o abrir una conexi6n de base de datos O C 6 m o enviar instrucciones SQL a bases de datos para su ejecucidn O C 6 m o extraer resultados devueltos de una consulta a una base de datos O Quk son las instrucciones preparadas O La funcidn de 10s tipos JDBC

A manejar excepciones y advertencias

Programacion de bases de datos con JDBC

Cargar un driver de base de datos y abrir conexiones


La interfaz j a v a .s q l .C o n n e c t i o n representa una conexi6n con una base de datos. Es una interfaz porque la implementaci6n de una conexi6n depende de la red, del protocolo y del vendedor. El API JDBC ofrece dos vias diferentes para obtener conexiones. La primera utihza j a v a .s q l .D r i v e r M a n a g e r y es adecuada para aplicaciones no gestionadas como clientes de base de datos Java aut6nomos. El segundo enfoque esti basado en el paquete j a v a x .s q l que introduce la noci6n de fuentes de datos y es adecuado para el acceso a bases de datos en aplicaciones J2EE. Comencemos considerando c6rno se obtienen las conexiones utilizando la clase j a v a . s q l . D r i v e r M a n a g e r . En una sola aplicaci6n, podemos obtener una o mis conexiones para una o mis bases de datos utilizando diferentes drivers JDBC. Cada driver implementa la interfaz j a v a . s q l . D r i v e r . U n o de 10s rnetodos que define esta interfaz es el metodo c o n n e c t ( ) que establece una conexi6n con la base de datos y devuelve un objeto c o n n e c t i o n que encapsula la conexi6n de base de datos. En lugar de acceder directamente a clases que implementan la interfaz j a v a .s q l .D r i v e r , el enfoque estindar para obtener conexiones es registrar cada driver con j a v a .s q l .D r i v e r M a n a g e r y utilizar 10s metodos proporcionados en esta clase para obtener conexiones. j a v a .s q l .D r i v e r M a n a g e r puede gestionar rnGltiples drivers. Antes de entrar en 10s detalles de este enfoque, necesitarnos entender c6mo JDBC representa la posici6n de una base de datos.

Los URL de JDBC


La noci6n de un URL en JDBC es muy similar al modo en que 10s URL se utilizan en otras situaciones. Para poder entender la base ldgica de 10s URL de JDBC, consideremos una aplicacidn que utiliza diversas bases de datos; a cada base de datos se accede mediante un diferentes driver debase de datos. En tal situaci61-1, ic6rno identificamos de forma exclusiva un driver? Ademis, las bases de datos utilizan diferentes tipos de parimetros para obtener conexiones. i C 6 m o se especifican 10s parimetros al establecer las conexiones? Los URL de JDBC proporcionan un modo de identificar un driver de base de datos. U n URL de JDBC representa un driver y la informaci6n adicional especifica del driver para localizar una base de datos y conectarla a 61. La sintaxis del URL de JDBC es como sigue:

Tiene tres partes separadas por dos puntos:


0 0

Protocolo: En la sintaxis anterior, jdbc es el protocolo. ~ s t es e el h i c o protocolo permitido en JDBC. Sub-protocolo: El sub-protocolo es utilizado para identificar un driver de base de datos, o el nombre de un mecanismo de conectividad de una base de datos, elegido por 10s proveedores del driver de la base de datos.

O Subnombre: La sintaxis del subnombre es especifica de driver. U n driver puede elegir cualquier sintaxis apropiada para su implementaci6n.
Por ejernplo, para una base de datos Cloudscape llamada "Movies", el URL a1 que debe conectar es:

Capitulo 4
Alternativamente, si estuvikramos utilizando Oracle mediante el puente JDBC-ODBC, nuestro U R L seria:

donde Movies es D N S establecido utilizando un administrador de driver ODBC. C o m o puede ver, 10s URL de JDBC son lo suficientemente flexibles como para especificar informaci6n especifica del driver en el subnombre.

DriverManager
El prop6sito de la clase j ava .sql .DriverManager (gestor de drivers) en JDBC es proporcionar una capa de acceso comGn.encima de diferentes drivers de base de datos utilizados en una aplicaci6n. En este enfoque, en lugar de utilizar clases de implementaci6n Driver individuales directamente, las aplicaciones utilizan la clase DriverManager para obtener conexiones. Esta clase ofrece tres mktodos estiticos para obtener conexiones. Sin embargo, Drive rManager requiere que cada driver que necesite la aplicaci6n sea registrado antes de sepa r que esti ahi. su uso, de mod0 que el ~ r i v e r ~ a n a g e El enfoque JDBC para el registro de un driver de base de datos puede parecer oscuro al principio. En JDBC, intente cargar el driver de base de datos utilizando el actual j ava. lang.ClassLoader.Fijese en el siguiente fragmento de codigo, que carga el driver de base de datos de Cloudscape:
try { Class.forName("COM.cloudscape.core.JDBCDriver"); } catch (ClassNotFoundException e ) { / / Driver no encontrado.

En el tiempo de e j e c u c h , elClassLoader localiza y carga la clase COM.Cloudscape .core. JDBCDriver desde alclasspathutihandoel cargadordeclase de autoarranque (bootstrap). Mientras carga una clase, el cargador de clase ejecuta cualquier c6digo estitico de inicializaci6n para la clase. En JDBC, se requiere que cada proveedor de driver registre una instancia del driver con la clase j ava .s ql .DriverManager durante esta inicializaci6n estitica. Este registro tiene lugar automiticamente cuando el usuario carga la clase del driver (utilizando la llamada Class. forName ( ) como anteriormente). j ava .sql .DriverManager es unaclase estiticay proporciona el siguiente metodo para este prop6sito:
public static void

registerDriver(java.sq1.Driver)

Alternativamente, podemos especificar una lista de drivers utilizando el mecanismo de propiedades Java. Por ejemplo, el siguiente fragmento permitiria a la clase j ava .sql .Driv.erManagercargar la h a de drivers cuando se realizara un intento de establecer una conexi6n:
System.setProperty ("jdbc.driversSS, "C0M.cloudscape.core. JDBCDriver") ;

Puede especificar multiples drivers en forna de lista separada par dos puntos (:).
Una vez que el driver ha sido registrado con el j ava .sql .DriverManager,podemos utilizar sus m6todos estiticos para obtener conexiones. Mis adelante, en este mismo capitulo, examinaremos la interfaz j avax .sql .Datasource que proporciona una mejor alternativa a las aplicaciones j ava .sql .DriverManager de J2EE. Sin embargo, puede que todavia seanecesario queutilice j ava .sql . DriverManager para el acceso direct0 a bases de datos fuera de las aplicaciones J2EE.

Pro~ramacion de bases de datos con JDBC


La clase j a v a . s q l D r i v e r M a n a g e r especificalos siguientes tipos de m6todos:
0 Mktodos para gestionar drivers 0 MCtodos para obtener conexiones 0 Mktodos para registros

Examinemos cada una de estas ireas sucesivamente.

Mbtodos para gertionar drivers


Los siguientes mktodos gestionan drivers. Observe que estos mCtodos estin dirigidos a la implementacibn de drivers y a las herramientas que manipulan drivers:
public static void registerDriver (Driver driver)

Este mktodo es utilizado para registra un driver con el DriverManager. Una clase de driver recientemente cargada debe llamar este metodo para hacerse conocer por el DriverManager. Las clases que implementan la interfaz Driver llaman este metodo durante la inicializacidn estitica para registrar una clase. Una vez registrada, el gestor de driver alberga una referencia a1 driver hasta que Cste es desregistrado. Por razones de seguridad, el gestor de driver asocia el cargador de clases del llamante con cada driver, de mod0 que las clases cargadas desde un cargador de clase tengan acceso Gnicamente a aquellos drivers que son registrados por clases cargadas por el mismo cargador de clases.
public static void deregisterDriver (Driver driver)

Este mitodo desregistra un driver del gestor de drivers.


public static Driver getDriver (String url)

Dado un URL de JDBC, este metodo devuelve un driver que puede entender el URL.
public static Enumeration getDrivers0

Este mktodo devuelve una enumeraci6n de todos 10s drivers registrados JDBC registrados por clases utilizando el mismo cargador de clase.

Metodos para obtener conexiones


El gestor de drivers tiene tres variantes de mktodo estitico g e t c o n n e c t i o n ( ) utilizado para establecer conexiones. El gestor de drivers delega estas llamadas en el mktodo c o n n e c t ( ) de la interfaz java.sql.Driver. Dependiendo del tip0 de driver y del servidor de base de datos, una conexi6n puede conllevar una conexi6n de red fisica a1 servidor de base de datos o un proxy a una conexion. Las bases de datos integradas no requieren conexi6n fisica. Haya o no una conexion fisica, el objeto de conexi6n es el Gnico objeto que utiliza una conexi6n para comunicar con la base de datos. Toda comunicaci6n debe tener lugar dentro del context0 de una o mis conexiones. Consideremos ahora 10s diferentes mktodos para obtener una conexi6n:
public static Connection getConnection(String url) throws SQLException

j a v a .s q l D r i v e rManage r recupera un driver apropiado del conjunto del drivers JDBC registrados. El URL de la base de datos esth especificado en forma de j d b c : s u b p r o t o c o l : subname. Q u e obtengamos o no una conexi6n con este mitodo depende de que la base de datos acepte o no solicitudes de conexi6n sin autentificaci6n.

public static Connection getconnection (String url, java.util.Properties info) throws SQLException

Este metodo requiere un U R L y un objeto java.util. Properties. El objeto Properties contiene cada parimetro requerido para la base de datos especificada. La lista de propiedades difiere entre bases de datos. Dos propiedades c o m h m e n t e utilizadas para Cloudscape con autocommit=true y create = fa1se.Podemos especificar estas propiedades junto con el URL como jdbc:Cloudscape :Movies; autocommit=true;create=trueopodemosestablecerestas propiedades utilizando el objeto Properties y pasar el objeto Properties en el mktodo anterior getconnection 0.
String url = "jdbc:cloudscape:Movies"; Properties p = new Properties( ) ; p.put("autocommit", "true"); p.put ("create","true"); Connection connection = DriverManager.getConnection(ur1,

p);

El driver descuida las propiedades n o existentes; si el valor de la propiedad no es vilido, puede obtener una excepci6n. Observe que estas propiedades son especificas del driver y debe recurrir a su documentaci6n del driver para obtener la lista de propiedades requeridas. Para saber mis sobre las propiedades disponibles para Cloudscape 4.0, dirijase ahttp://www.cloudscape.con\/docs/doc~40/doc/html/coredocs/attrib.htm.
public static Connection getConnection(String url, String user, String password) throws SQLException

La tercera variante toma usuario y contrasefia como argumentos ademis del URL. ~ s t es e un ejemplo; el siguiente codigo utiliza un driver ODBC, donde Movies es un DNS fijado en la configuracidn de ODBC. Este D N S corresponde a una base de datos que requiere un nombre de usuario y una contrasefia para obtener una conexion:
String url = "jdbc:odbc.Movies "; String user = "catalog admin"; String password = "catalog admin"; Connection conn
=

DriverManager.getConr~ection(url, user, password);

Observe que todos estos mktodos estin sincronizados,lo que supone que mis de un thread de aplicaci6n no puede conseguir el mismo objeto j ava .sql .connection.Estos metodos lanzan una excepci6n SQLExcept ion si el driver no consigue obtener una conexi6n. En ocasiones es necesario especificar el tiempo miximo que debe esperar un driver mientras intenta conectar a una base de datos. Los siguientes dos mktodos pueden ser utilizados para fijarlobtener el tiempo limite de registro:
public static void setLoginTimeout(int seconds) public static int getLoginTimeout()

El valor por defect0 para el tiempo limite de registro es especifico del driverlbase de datos.

M e t o d o r de registro
Los siguientes mktodos acceden o establecen un objeto printwriter con propdsitos de registro:
public static void setLogWriter(PrintWriter out)

Procramacion de bases de datos con JDBC


public static Printwriter getlogwriter
()

Ademis, las aplicaciones cliente tambien puden registra mensajes utilizando el siguiente mitodo:
public static void println(String message)

Este metodo es utilizado junto con P r i n t w r i t e r establecido por el metodo s e t L o g W r i t e r ( ) para imprimir mensajes de registro.

En JDBC, cada driver es identificado utilizando un URL de JDBC, y cada driver debe implementar la interfaz j a v a s q l D r i v e r . Por ejemplo, en Cloudscape, la clase COM. C l o u d s c a p e c o r e . J D B C D r i v e r implementalainterfazj a v a s q l .~ r i v e r , q u e e s p e c i f i c a l o s siguientes mktodos:

. .

public public public public public public

boolean acceptsURL (String url) Connection connect(String url, Properties info) int getMajorVersion0 int getMinorVersion0 DriverPropertyInfo getPropertyInfo(String url, Properties info) boolean jdbcCompliant()

La clase D r i v e r M a n a g e r utiliza estos mitodos. En general, las aplicaciones cliente n o necesitan acceder directamente a las clases de driver.

Establecer una conexion


Para comunicar con una base de datos utilizando JDBC, debemos en primer lugar establecer una conexi6n con la base de datos a traves del driver JDBC apropiado. El API de JDBC especifica la conexi6n en la interfaz j a v a s q l . C o n n e c t i o n . Esta interfaz tiene 10s siguientes mitodos pbblicos:

Crear instrucciones Obtener informacibn de bases de datos Apoyo de transacciones getMetaData ( ) s e t A u t o C o d t () g e t A u t o C o d t () commit ( ) r o l l b a c k ( ) setTransactionIsolation() getTransactionIsolation() isclosed () close () setReadOnly ( ) isReadOnly ( ) clearwarnings () getwarnings ( ) nativeSQL ( ) setcatalog () getcatalog () setTypeMap ( ) qetTvPeMaP ( )

valOresd

Estado de conexion y cierre Configurar diversas propiedades, limpiar recuperar cualquier advertencia genera a

Convertir strings SQL en SQL especifico de base de datos y configurar vistas y tipos definidos por el usuario

Capitulo 4
Las categorias de la tabla anterior representan un intento de descomponer 10s metodos en grupos lbgicos segun sus funcionalidad. En las siguientes secciones, estudiaremos la mayoria de estos metodos. ~ s t es e un ejemplo de establecimiento de una conexi6n JDBC a la base de datos C l o u d s c a p e ~ o v i e s :
Connection connection; String url = "jdbc:cloudscape:Movies;create=true"

connection

DriverManager.getConnection(ur1);

/ / Acceso a datos utilizando el objeto de conexi6n

. .
)

catch (SQLException e ) { / / Tratar el error aqui finally { try 1 connection. close ( ) ; 1 catch(SQLException e ) { / /

System error?

En este ejemplo, el URL especifica el URL de JDBC; c r e a t e = t r u e indica que Cloudscape deberia crear la base de datos M o v i e s si 6sta no existe. Siempre debe capturar la excepci6n S Q L E x c e p t i o ne intentar cerrar la conexi6n despuCs de utilizar la conexibn para acceso a 10s datos. En el APT de JDBC, hay varios metodos que lanzan una exception S Q L E x c e p t i o n . En este ejemplo, la conexi6n se cierra a1 final del bloque f i n a l l y , de mod0 que 10s recursos del sistema pueden ser liberados independientemente del Cxito o fracas0 de cualquier operaci6n de base de datos. Resumamos ahora lo que hemos analizado hasta el momento utilizando un ejemplo sencillo. Este ejemplo registra el driver Cloudscape y establece una conexi6n:
/ / Importar paquetes requeridos import j ava. sql. Driver; import j ava. sql. DriverManager; import j ava. sql .Connection; import j ava. sql. DatabaseMetaData; import j ava. sql . SQLException; import j ava .sql.DriverPropertyIr~fo; import j ava. util. Enumeration; import java.util.Properties;
public class DriverTest { public static void main(String arg[]) { String protocol = " jdbc:cloudscape: c: /CloudscapeDBU; String driverclass = "C0M.cloudscape.core.JDBCDriver";
/ / Registrar el driver Cloudscape try 1 Class.forName(driverC1ass); ) catch (ClassNotFoundException cne) { cne. printStackTrace ( ) ; 1. / / Comprobar 10s drivers registrados Enumeration drivers = DriverManager.getDrivers ( ) ; while (drivers.hasMoreElemer1ts i ) ) 1 Driver driver = (Driver) drivers. nextElement [ ) ; System.out .println ("Registered driver: "

driver.getClass0.getNamei));

Programacion de bases de datos con JDBC

/ / Acepta este driver el URL conocido if (driver.acceptsURL(protoco1)) I System.out .println ("Accepts URL: "
1

protocol);

1 catch

(SQLException sqle) sqle.printStackTrace0;

t
\

/ / . O b t e n e r una c o n e x i 6 n d e l DriverManager. try I C o n n e c t i o n c o n n e c t i o n = DriverManager.getConnection(protoco1); / / Obtener 10s rnetadatos DatabaseMetaData metaData System.out.println("Product
)

connection.getMetaData(); name: " + metaData.getDatabaseProductName()); S y s t e m . o u t . p r i n t l n ( " D r i v e r n a m e : " t m e t a D a t a .getDriverNarne ( catch (SQLException sqle) [ sq1e.printStackTrace ( ) ;
=

) ) ;

Este ejemplo ejecuta tres tareas cuyo prop6sito es acercarle 10s fundamentos de la programaci6n JDBC:
0 La primera tarea es registrar un driver. Puesto que 10s drivers realizan este registro via inicializacion estitica, todo lo que tiene que hacer es cargar el nombre de clase para el driver especifico que esti utilizando. En este ejemplo, registramos el driver para Cloudscape. Observe que puede registrar mis de un driver de una aplicaci6n dada. 0 La segunda tarea es encontrar cuiles son 10s drivers registrados. Utilizamos java.sql.DriverManager para encontrar una enumeraci6n de 10s drivers registrados en ese momento. Como solo hemos registrado un driver en el primer paso, el segundo paso encontrari s d o un driver. El segundo paso tambikn determina si el driver encontrado acepta el URL conocido. En este caso, determinamos si el driver acepta el URL " jdbc :Cloudscape : c : / CloudscapeDB", donde " c : / c l o u d s c a p e D ~es " el nombre (y localizaci6n) de la base de datos para esta aplicaci6n. 0 El tercer paso es obtener una conexi6n a la base de datos utilizando el mktodo getconnection ( ) en java. sql .~riverManager.Despuksdeobtenerlaconexion, tambikn encontramos algunos de 10s metadatos de la base de datos utilizando j ava .sql DatabaseMetadata obtenidoinvocandoelm6todoget~eta~ata ( ) en java.sq1.Connection.

Para poner a prueba este ejemplo, debe axiadir las librerias Cloudscape a su classpath. La principal que requerimos para este ejemplo es cloudscape .j ar,que encontrari en % J 2 E E ~ H O M E % \ l i b \ c l o u d s c a p e ( o % J 2 E E % J 2 E E _ H O M E g \ l i b \ c l o u d s c a p e ( o % J 2 E E _ H O M E % \ H O M E % \ 1 i b \ ~ y s t e m ) . Despu6s de configurar este classpath, compile y ejecute esta clase. Para Cloudscape 3.6.4, la salida de esta clase seri como sigue:

Capitulo 4

~ s t incluye e el nombre de clase del driver, el URLaceptado, el nombre del producto y el nombre del driver. Fijese en que el nombre del driver es algo criptico. Esto se debe a que las librerias Cloudscape son confundidas para prevenir la descompilaci6n.

Crear y ejecutar instrucciones SQL


Podemos utilizar un objeto Connection para ejecutar instrucciones SQL creando un statement, un Preparedstatement o un Callablestatement.Estos objetos abstraen instrucciones SQL normales, instrucciones preparadas y procedimientos almacenados respectivamente. Una vez hemos obtenido uno de esos objetos de instrucciones, podemos ejecutar la instrucci6n y leer 10s resultados gracias a un objeto ResultSet. Como hemos mostrado en la tabla anterior, 10s siguientes mttodos crean objetos de instrucciones:
Statement createstatement0 throws SQLException

Este mttodo crea un objeto statement, que podemos utilizar para enviar instrucciones SQL a la base de datos. Las instrucciones SQL sin pardmetros son ejecutadas normalmente utilizando objetos
Statement.
Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException

Esta variante de createstatement ( ) requiere el Tipo Result Set y argumentos resultSetconcurrency.Estos argumentos se aplican a objetos ResultSet creados ejecutando consultas. De estos dos argumentos, el primero es utilizado para especificar el tipo ResultSet requerido. Como veremos mds adelante, existen tres tipos de resultados dependiendo de su capacidad de desplazamiento: desplazables s61o hacia adelante (ResultSet.TYPE-FORWARD-ONLY), desplazables pero insensibles a 10s cambios realizados por otras transacciones (ResultSet.TYPE-SCROLL-INSENSITIVE) o desplazables y sensibles a 10s cambios realizados por otras transacciones (ResultSet .TYPE-SCROLL-INSENSITIVE). Lainterfazjava. sql. ~ e s u l t ~ e t e s p e c i f i c a t r e s constantes como tipos de resultados. El segundo argumento es utilizado para especificar si el Result set es de s61o lectura (ResultSet. CONCUR-READ-ONLY) o deberiaseractualizable (Result Set. CONCUR-UPDATEABLE). El mttodo de no argumento createstatement hacia adelante y de s d o lectura.
()

devuelve un ~ e s u l set t que s61o es desplazable

Programacion de bases de datos con JDBC


El mCtodo createstatement ( ) no toma argumentos (except0 para tip0 y concurrencia donde sean aplicables) y devuelve un objeto statement. El objetivo final de un objeto statement es ejecutar una instrucci6n SQL que puede o no devolver resultados. Veremos un ejemplo pr6ximamente.
public Preparedstatement prepareStatement(Strin9 sql) throws SQLException

Podemos obtener un objeto Preparedstatement invocando este metodo en una connection.Mis adelante en este capitulo, haremos un recorrido por el uso de instrucciones preparadas para ejecutar instrucciones SQL.
public Callablestatement preparecall (String sql) throws SQLException

Este metodo es utilizado para invocar un procedimiento almacenado. La interfaz statement tiene 10s siguientes mCtodos:

Ejecutar instrucciones

execute ( ) executeQuery ( ) executeupdate ( )

Actualizaciones lotes

Tamaho de toma de resultset

Obtener resultset actual Resultset concurrency and type Otros


setQueryTimeout ( ) getQueryTimeout ( ) setMaxFieldSize ( ) getMaxFieldSize ( ) cancel ( ) getconnection ( )

Statements tambikn se ajusta a 10s mismos mktodos para transacciones que el objeto connection, junto con el metodo close ( ) .

Hay dos subinterfaces Prepareds tatement y CallableS tatement,que son utilizadas para invocar instrucciones SQL precompiladas y procedimientos almacenados de base de datos. Estas dos interfaces especifican mktodos adicionales para preparar instrucciones e invocar procedimientos almacenados.

Un ejemplo: catiilogo de peliculas


Para ilustrar el API JDBC, consideremos un simple catilogo de peliculas. La base de datos para este ejemplo consiste en una tabla llamada CATALOG. Consideremos una clase Java CreateMovieTable que Cree una tabla CATALOG e inserte 10s datos en la tabla. En este ejemplo, recuperamos 10s datos de un archivo de texto, catalog. txt,y 10s insertamos en la CATALOG.

209

Capitulo 4
Crear la tabla Movie

El rnCtodo i n i t i a l i z e ( ) carga el driver y obtiene una conexi6n. c r e a t e t a b l e ( ) crea la tabla. Puede utilizar el siguiente mktodo en el objeto s t a t e m e n t para insertar datos:
int executeUpdate(String
sql) throws SQLException

e x e c u t e U p d a t e ( ) es utilizado para ejecutar instrucciones SQL que no devuelven ning6n resultado, por ejernplo instrucciones INSERT, UPDATE o DELETE. Este rnCtodo devuelve un nGrnero entero que denota el n h n e r o de las filas afectadas:
public class CreateMovieTables { static String driver = "COM.cloudscape.core.JDBCDriver"; static String url = "jdbc:cloudscape:"; Connection connection = null; Statement statement = null; / / ... public void initialize ( ) throws SQLException, ClassNotFoundException [ Class.forName (driver); + "Movies;create=trueW); connection = DriverManager.getCor~r~ectior~(url

I
public void createTable() throws SQLException [ statement = connection.createStatement(); statement.executeUpdate("CREATE TABLE CATALOG" + " (TITLE VARCHAR(256) PRIMARY KEY NOT NULL, "LEAD ACTOR VARCHAR(256) NOT NULL, " + "LEAD ACTRESS VARCHAR(256) NOT NULL, " + "TYPE VARCHAR(20) NOT NULL, " + "RELEASE DATE DATE NOT NULL)");

"

I
En este c6dig0, las variables c o n n e c t i o n y s t a t e m e n t son variables de instancias de la clase ( ) obtieneunaconexi6nde~~river~anager.Para CreateMovieTables.ElrnCtodocreate~able Cloudscape, especificarnos e~protoco~ocorno" j d b c :c l o u d s c a p e : M o v i e s ; c r e a t e = t r u e n . Cuando crearnos una tabla por prirnera vez utilizando este URL, Cloudscape DMBS crea un subdirectorio bajo el directorio actual llarnado " M o v i e s " para alrnacenar 10s datos. Consulte la docurnentaci6n Cloudscape para especificar un directorio diferente. En caso de que desee lirnpiar su base de datos, puede elirninar este directorio y volver a crear todas las tablas. Puede acceder a la docurnentaci6n de Cloudscape online enhttp://www.cloudscape.comlsupportldocumentation.html. En el c6digo anterior, el e x e c u t e U p d a t e ( ) no actualiza ning6n registro de la base de datos y por ello el rnktodo devuelve cero. En el caso de las instrucciones INSERT, UPDATE o DELETE puede que estC interesado en el nfirnero de filas insertadas, actualizadas o elirninadas, respectivarnente. Observe tarnbikn que el esquema utilizado en este ejernplo es s61o con fines ilustrativos y no refleja de una forma realista 10s datos del catilogo. DespuCs de conseguir una conexion, el siguiente paso es crear una instruccibn. Pasamos una instrucci6n SQL para crear la tabla utilizando el mCtodo e x e c u t e u p d a t e ( ) en la instrucci6n. Como puede ver en la instrucci6n anterior, la tabla CATALOG tiene cinco columnas.
lnsertar datos

El mktodo i n s e r t D a t a ( ) de la c l a s e ~ r e a t e ~ o v i e ~ a b lee l eregistros s de pelicula de una archivo de texto y 10s inserta en la base de datos:

Programacion de bases de datos con JDBC


public void insertData ( ) throws SQLException, IOException { BufferedReader br = new BufferedReader(r1ew FileReader("catalog.txt"));

title = br.readLine( ) ; 1eadActor = br. readline ( ) ; 1eadActress = br. readline ( ) ; type = br. readline ( ) ; dateOfRelease = br.'read~ine ( ) ; String sqlString
=

"INSERT INTO CATALOG " t " (TITLE, LEAD ACTOR, LEAD ACTRESS, "t "TYPE, RELEASE DATE) " t "VALUES(\" t title t "',"' t 1eadActor t "',"' t 1eadActress "\,"' t type t "',"' t dateOfRelease t

t "\)";

staternent.executeUpdate(sq1String); statement. close ( ) ; while(br.readLine ( ) ! = null); / / This reads the termination line

]
}

catch (IOException e ) e.printStackTrace() finally { br. close ( ) ;

I
Elformato delarchivo deentradaes t i t u l o , a c t o r p r i n c i p a l , a c t i z p r i n c i p a l , t i p 0 y f e c h a d e E s t r e n o introducidos en lineas separadas, seguidos de una linea separatoria como se muestra a continuaci6n:
Austin Powers Mike Myers Liz Hurley Comed y 1999-04-01

En el c6digo anterior, la unica instrucci6n que es relevante para nuestro anilisis es el mCtodo s t a t ement e x e c u t eUpdat e ( ) invocado para insertar 10s datos en la tabla CATALOG. Observe que n o capturamos aqui S Q L E x c e p t i o n .En su lugar, estamos dejando a1 llamante de este mCtodo capturar la excepci6n SQL.

Metodos para el manejo de excepciones


C o m o hemos mencionado con anterioridad, la mayoria de 10s mCtodos en las interfaces y clases JDBC lanzan una instancia de SQLExcepti o n para indicar que hay un fallo. Sin embargo, dependiendo de 10s drivers y las bases de datos que est.6 utilizando, podri haber varias capas y fuentes de error. Para acomodar esto, la excepci6n S Q L puede ser anidada, integrando diversas excepciones en una lista vinculada. Podemos utilizar el metodo g e t N e x t E x c e p t i o n ( ) en la clase SQLExceptionpara recuperar todas esas excepciones. El siguiente fragment0 de c6digo recorre recursivamente las excepciones disponibles. Este enfoque puede resultar informativo para el manejo de excepciones en nuestras aplicaciones JDBC:

while (sqlException ! = null) {

Capitulo 4

De un modo similar, puede recuperar advertencias (incluido las especificas del vendedor) recibidas o generadas por el driver utilizando el metodo getwarnings ( ) en la conexi6n:
SQLWarrling warnings
=

connection.getWarnings

( );

while(warnings ! = null) { System.err.println ( c o n n e c t i o n . g e t W a r r i i n g s warnings = warnings. getNextWarning ( ) ;

( ) ) ;

I
~ s t es a la fuente completa:
import import import import import import import import import import import import
//
j ava. sql. DriverManager;

j ava. sql. Connection; j a v a .sql .Statement; java.sq1.PreparedStatement; java.sql.SQLException; j ava. sql . Date; java.io.BufferedReader; java. i o . FileReader; j ava. io. IOException; j ava. io. EOFException; java.text.Simp1eDateForrnat; j ava. text. ParseExcept ion; que

Esta clase requiere un archivo d e texto Llamado catalog.txt contenga / / 10s datos d e entrada. public class CreateMovieTables
{

static String driver = "COM.cloudscape.core.JDBCDri~er"; static String url = "jdbc:cloudscape:"; String title, leadActor, Connection connection; Statement statement; public void initialize ( ) Class.forName(driver); leadActress, type, dateOfRelease;

throws SQLException, ClassNotFoundException {

.getConr~ection (url + "Movies; create=trueT'); conr~ection = DriverMar~ager


)

public void c r e a t e T a b l e 0 throws SQLException [ statement = connection. createstaterner~t( ) ; statement.executeUpdate("CREATE TABLE CATALOG" + "(TITLE VARCHAR(256) PRIMARY KEY NOT NULL, " + "LEAD ACTOR VARCHAR (256) NOT NULL, " + "LEAD ACTRESS VARCHAR(256) NOT NULL, " + "TYPE VARCHAR(20) NOT NULL, " + "RELEASE DATE DATE NOT NULL) " ) ;
1

public void i n s e r t D a t a 0 throws SQLException, IOException { BufferedReader b r = r ~ e w BufferedReader(r1ew FileReader("catalog.txt")i;

Programaci6n de bases de datos con JDBC

title = br. readline ( ) ; leadActor = br. readline ( ) ; 1eadActress = br. readline ( ) ; type = br. readline ( ) ; dateOfRelease = br. readline ( ) String sqlstring
=

"INSERT INTO CATALOG " + "(TITLE, LEAD ACTOR, LEAD ACTRESS, " + "TYPE, RELEASE DATE) " + "VALUES( "' + title + 11 \ , + leadActor + "',"' + leadActress + "',"' + type t "',"' + dateOfRelease + " ' ) " ;
1 1 1

statement.executeUpdate(sq1String); statement.close(); while (br.readLine() ! = null); / / This reads the termination line

catch (IOException e ) { e.printStackTrace ( ) ; finally { br.close0;

I I
public void close ( ) throws SQLException 1 try I connection. close ( ) ; ) catch (SQLException e ) { throw e;

public static void main (String arg [ 1 ) { CreateMovieTables movies = new CreateMovieTablesO; try i movies.initialize(); rnovies.createTable() ; movies.close(); ] catch (SQLException sqlException) { while (sqlException ! = null) { sq1Exception.printStackTrace ( ) ; sqlException = sqlException.getNextExceptior~ ( ) ;

I
]

catch (Exception e) { e.printStackTrace ( ) ;

I
1

C o n objetivos de demostraci61-1, esta clase e s t i estructurada en terminos de pequefios metodos, cada uno de 10s cuales desempefia funciones JDBC especificas. En esta clase, el metodo i n i t i a l i z e ( ) carga el driver y crea una conexi6n. El metodo c r e a t e T a b l e ( ) crea una tabla utilizando el metodo e x e c u t e u p d a t e ( ) enlainstrucci6n j a v a . s q l . S t a t e m e n t . El m e t o d o i n s e r t ~ a t a ( ) leeunaserie de registros de un archivo de texto y 10s inserta en la tabla. El metodo m a i n ( ) de esta clase es el controlador que invoca 10s otros metodos en secuencia. Observe que el metodo m a i n ( ) invoca el metodo c l o s e ( ) para cerrar la instrucci6n y la conexi6n.

Capitulo 4
Fijese que de 10s campos insertados en el mitodo anterior, aunque el campo RELEASE-DATE es de tip0 DATE, utilizarnos un string a1 crear la instrucci6n. Esto es vilido siempre que el String utilizado pueda ser forzado de forrna segura en un carnpo DATE. En este ejemplo, el string utilizado es de la forrna YYYYMM-DD, que es traspasable a un carnpo DATE. Sin embargo, para que Sean seguros, debe considerar utilizar instrucciones preparadas para ejecutar SQL que conlleve datos introducidos corno fechas, estampillas de tiernpo, nfirneros, etc. Para la mayor parte de 10s ejernplos restantes de este capitulo, seguiremos la clase anterior corno plantilla. Si desea experirnentar con el APIJDBC, debe ariadir nuevos rnitodos a esta clase.

Consultar la base de datos


El o b j e t o s t a t e m e n t devuelve un objeto j a v a . s q l . R e s u l t S e t que encapsulalos resultados de ejecuci6n. Esta es una interfaz que es implernentada por vendedores de drivers. Puede desplazar 10s bloques de resultados utilizando un cursor para leer 10s resultados en R e s u l t s e t. El siguiente r n C t o d o , e x e c u t e Q u e r y 0, en lainterfaz j a v a . s q l . S t a t e m e n t le perrnite ejecutarlas instrucciones SQL SELECT:
public ResultSet executequery
:

(String sql) throws SQLException

Existe tarnbikn un rnitodo genirico e x e c u t e ( ) que puede devolver multiples resultados:


public boolean execute(String sql) throws SQLException

Este metodo execute() puede utilizarse para ejecutar procedimientos almacenados conocidos para ofrecer mdtiples resultados o strings SQL desconocidas (por ejemplo, instrucciones SQL leidas en otras fuente en el tiempo de ejecuci6n). Este rnetodo devuelve un Boolean con valor true cuando la ejecuci6n tiene como resultado uno o rnis bloques de resultados, o un valor false cuando la ejecuci6n tiene como resultado una o mis cuentas de actualizaci6n. Utilizando este valor de retorno, la aplicaci6n puede invocar 10s rnetodos getResult () o getupdate() para acceder al bloque de resultados o actualizar la cuenta, respectivarnente. El API JDBC 2.1 introduce dos tipos rnis de ResultSet que perrniten desplazar 10s resultados hacia adelante y hacia atris per0 no todos 10s vendedores de bases de datos se ajustan en la actualidad a esta caracteristica. Analizaremos el desplazamiento de resultados posteriorrnente en este capitulo.

Metodos para recuperar datos


La interfaz j a v a s q l ~ e s u lSte t ofrece varios rnitodos para recuperar carnpos de diferentes tipos. Dependiendo de su esquema, deberi utilizar 10s rnetodos apropiados para recuperar 10s datos: getArray ( ) getBlob ( ) getcharacter Stream0 GetFloat getRef
() ()

getAsciiStream() getBoolean ( ) getClob


()

getBigDecimal() 9etByte () getDate ( ) getLon9 ( ) getstring ()

getBinaryStream getBytes
()

getDouble ( ) getobje c t () getTime ( )

getInt () getshort () getURL ( )

getTimestamp ( )

Programacion de bases de datos con JDBC


Todos estos metodos requieren el nombre de la columna (como un string) o el indice de la columna como argumento. La sintaxis para las dos variantes de 10s mitodos getstring ( ) son las siguientes:
public String getString(int columnIndex) throws SQLException public String getString(String columnlame) throws SQLException

En casos en 10s que el indice de la columna estd sujeto a1 cambio debido a cambios en SQL o en el esquema de la base de datos es preferible utilizar nombres de columna en estos metodos. Los tipos devueltos de estos mitodos varian desde simples primitivas Java como int,double,byte, etc., hasta tipos SQL de prop6sito especifico como j ava .sql lob y java .sql lob. Los metodos getAsciiStream(),getBinaryStream(,)ygetCharacterStream() permitenelaccesoadatos ASCII/caracteres arbitrariamente largos devolviendo objetos j ava . io . Inputstream y j ava.io.Reader. Volvamos a nuestro catdogo de peliculas y creemos otra clase, Que ryMovieTable,para implementar diferentes tipos de consultas. El siguiente mitodo, queryAll ( ) , recupera todos 10s datos de la tabla CATALOG:
public void queryAll(1 throws SQLException { Systern.out.println("Query All") ; Statement statement = connection. createstatement ( ) ; String sqlstring
=

"SELECT CATALOG.TITLE, CATALOG.LEAD ACTOR, "CATALOG. LEAD ACTRESS, CATALOG. TYPE, " + "CATALOG.RELEASE DATE FROM CATALOG";

"+

ResultSet

rs

statement.executeQuery(sqlString);

while (rs.next ( ) ) { System.out .println(rs.getString("TITLEt') t ", " t rs .getString,("LEAD ACTOR") t ", " t rs.getStringiMLEAD ACTRESS") t ", " t rs.qetString("TYPE") t ", " t rs.getDate("RELEASE DATE"));

Este m i t o d o crea primero un objeto statement,que utiliza entonces para invocar executeQuery ( ) con una instrucci6n SELECT SQL como argumento. El objeto j ava .sql .ResultSet contiene todas las filas de la tabla CATALOG que coinciden con la instrucci6n SELECT. Utilizando el metodo next ( ) del objeto ResultSet,podemos repetir todas las filas contenidas en el bloque de resultados. En cualquier fila, podemos utilizar uno de 10s mitodos getXXX de la tabla anterior para recuperar 10s campos de una fila. i Q u e sucede si la consulta (o cualquier SQL enviado a la base de datos a traves del driver para su ejecuci6n) es muy cara y tarda mucho tiempo en completarse? Esto puede ocurrir, por ejemplo, si la consulta es compleja o si la base de datos esti intentando devolver un gran ndmero de resultados. Para controlar el tiempo que espera el driver para que la base de datos complete su ejecucibn, la interfaz j ava .sql . statement tiene dos mktodos para obtener o fijar un limite mdximo de tiempo. Por ejemplo, podemos modificar el metodo quer y ~ l (l ) para establecer un intervalo de tiempo miximo para la consulta (en segundos) utilizando el mitodo setQueryTimeout ( ) . Puede utilizar el metodo getQueryTimeout ( ) para conocer el intervalo de tiempo de la consulta en segundos (o el valor por defecto, si n o se ha fijado explicitamente). Una vez que la base de datos excede el intervalo miximo de tiempo, el driver aborta la ejecuci6n y lanza una excepci6n j ava .sqlSQLException.Por ejemplo, aqui fijamos el valor del plazo limite de tiempo en 1 segundo:

Capitulo 4
4

Statement staten~erlt = connection. createstatement ( ) ; statement.setQueryTimeout(1); / / Establecer SQL para la irjstrucci6n ; ResultSet rs = statement .executeQuery ( s q l s t r i n g )

lnterfazResultSetMetaData

La interfaz ResultSet tambien nos permite conocer la estructura del bloque de resultados. El metodo getMetaData ( ) nos ayudaa recuperarun objeto java. sql .ResultSetMetaData que tienevarios metodos para describir 10s cursores del bloque de resultados:
GetCatalogName ( ) getTableName ( ) Get SchemaName ( ) GetColumnCount ( ) GetColumnName ( ) ) GetColumnLabel ( ) GetColumnType ( )

Tomando un bloque de resultados, podemos utilizar el metodo getcolumncount ( ) para obtener el numero de columnas del bloque de resultados. Utilizando este numero de columnas, podemos obtener la meta-informaci6n de cada columna. Por ejemplo, el siguiente metodo de nuestro ejemplo imprime la estructura del bloque de resultados:
public vold g e t M e t a D a t a 0 throws SQLException { System.out .prlntln("MetaData o f ResultSet") ; Statement statement = connection.createStatement(); String sqlString ResultSet rs
=

"SELECT

* FROM CATALOG";

statement.executeQuery(sq1String);
=

ResultSetMetaData metaData int nocolumns


=

rs .getMetaData (
) ;

) ;

metaData.getColumnCount (

/ / Nhmero d e columna empezando desde el 1 for(int i = 1; i < nocolumns t 1; it+) { System.out.println(metaData.getColumnName(i) metaData. getColumnType(i)

+ "
) ;

"

I I
El metodo anterior obtiene el numero de columnas del bloque de resultados e imprime el nombre y el tip0 de cada columna. En este caso, 10s nombres de columna son TITLE, LEAD-ACTOR, LEAD-ACTRESS, TYPE y RELEASE-DATE. Observe que 10s tipos de columna son devueltos como numeros enteros. Por ejemplo, todas las columnas tipo VARCHAR tendrin el tipo de columna 12, mientras que el tipo DATE es

Programacion de bases de datos con JDBC


tipo 91. Estos tipos son constantes definidas en la interfaz j a v a .s q l . T y p e s . Fijese tambikn en que 10s numeros de las columnas empiezan desde 1 y no desde 0. Esta informaci6n puede utilizarse para decidir c6mo tratar este tip0 de datos. Por ejemplo, conociendo que la quinta columna es tipo DATE (fecha), la aplicaci6n puede determinar que un j a v a .s q l .D a t e deberia utilizarse para representar este dato. Aunque esta informaci6n puede derivarse del estudio del esquema de la base de datos y del SQL utilizado para extraer 10s datos, 10s metadatos de la base de datos pueden utilizarse para reducir la codificaci6n de dicha informaci6n.

lnstrucciones preparadas
Las instrucciones preparadas JDBC cumplen 10s siguientes requisitos:

Crear instrucciones parametrizadas de mod0 que 10s datos para parimetros puedan ser sustituidos dinimicamente

O Crear instrucciones que impliquen valores de datos que no siempre pueden ser representados como strings de caracteres
O

Precompilar instrucciones S Q L para evitar la compilaci6n repetida de las mismas instrucciones S Q L

Analicemos brevemente las razones de la importancia de estos requisitos. En la mayoria de 10s casos, puede que n o tenga la informacion completa para construir una cliusula DONDE en SQL. Por ejemplo, para escribir una instrucci6n SQL SELECT para seleccionar 10s datos de un usuario, mientras escribe el c6digo JDBC, necesita conocer el valor clave primario (como el USER-ID) para construir el SQL. En la mayor parte de 10s casos, esta informacion esti disponible s61o en el period0 de ejecuci6n (digamos, desde una interfaz de usuario o desde cualquier otra aplicaci6n). Las instrucciones preparadas se enfrentan este problema proporcionando parimetros (expresados como signos de interrogaci6n) en SQL. En lugar de utilizar valore, puede utilizar calificadores " ? " en SQL. Por ello, en vez de crear una instrucci6n con el string SQL:
SELECT

<select-fields\

FROM

<table-name>

WHERE

USER-ID

<value>

puede utilizar una instrucci6n preparada con el string SQL:


SELECT <select-fields> FROM <table-name, WHERE USER-ID
=

Puede sustituirvalores actuales utilizando mktodos en la interfaz j a v a . s q l . P r e p a r e d s t a t e m e n t . Lo mismo se aplica a SQL cuando conlleva tipos de datos complejos como datos de texto largo, datos binarios o incluso datos de estampillas de tiempo. Tales tipos de datos (durante inserciones/ actualizaciones o en cliusulas DONDE de SQL) n o pueden ser expresados como sencillos strings. Por ejemplo, k 6 m o creariamos una instrucci6n SQL para actualizar datos de imagen? Debido a que las instrucciones preparadas estin parametrizadas, en lugar de expresar esos tipos de datos en la instrucci6n SQL directamente, puede configurar 10s datos utilizando diversos metodos en la interfaz
java.sql.PreparedStatement.

Ademis, las mismas instrucciones SQL pueden ser ejecutadas varias veces con diferentes parimetros y la base de datos puede compilar estas instrucciones s61o una vez, mejorando asi el rendimiento. U n objeto P r e p a r e d s t a t e m e n t puede albergar instrucciones precompiladas. Los siguientes metodos de la interfaz j a v a . s q l .C o n n e c t i o n n o s permitencrear o b j e t o s ~ r e ~ a r e d ~ t a t e m e n t :

Capitulo 4
PreparedStatement prepareStatement(String sql) throws SQLException PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException

Por ejemplo, en el metodo i n s e r t D a t a ( ) dela c l a s e ~ r e a t e ~ o v i e ~ a b llainstrucci6n es, INSERT SQLes ejecutadavarias veces. Esta instruction debe ser compilada antes de ser ejecutada. La compilaci6n es un proceso que requiere tiempo y que conlleva normalmente el anilisis de la instruccih, asociando con las tablas y las columnas cualquier optimizaci6n y generaci6n de c6digo, por lo que puede que sea mis conveniente utilizar una instrucci6n preparada como alternativa. Con instrucciones preparadas, esta compilaci6n s610 se realiza una vez. Para permitirnos especificar 10s datos, las instrucciones estin parametrizadas, con cada parimetro representado como un signo de interrogaci6n ( ? ) . Podemos reemplazar el metodo i n s e r t D a t a ( ) de la clase C r e a t e M o v i e T a b l e s con lo siguiente para hacer uso d e l o b j e t o ~ r e p a r e d ~ t a t e m e n t :
public void insertPreparedData
=

( )

throws SQLException, IOException

Buf feredReader br

new Buf feredReader (new FileReader ("catalog.txt"! )

Preparedstatement preparedstatement = connection. preparestatement ("INSERT INTO" CATALOG" + "(title, lead actor, lead acctress, " + "type, release date)" + "VALUES[?, ?, ? , ?,
? ) ' I ) ;

SirnpleDateForrnat dateForrnat

new SirnpleDateForrnat("yyyy-MM-dd");

preparedStatement.clearParameters(); title = br.readLine(); leadActor = br. readline ( ) ; leadActress = br. readline ( ) ; type = br. readline ( ) ; dateOfRelease = br. readlir~e ( ) ; Date date = new Date(dateForrnat.parse(dateOfRelease).getTime());
preparedStaternent.setString(1, title); preparedstatement .setstring ( 2 , 1eadActor); preparedStatement.setString(3, 1eadActress); preparedstatement . setstring ( 4 , type) ; preparedstatement .setDate ( 5 , d a t e ) ;

while [br.readline ( ) ! = nu1 1 ) ; catch (EOFException e) { catch (java.text. ParseException pe) pe.printStackTrace ( ) ; catch (IOException ioException) J, ioException.printStackTrace(); finally { preparedStatement.close0; br. close ( ) ;

Una vez se ha creado P r e p a r e d S t a t e m e n t , utilice 10s mCtodos s e t x x x para fijar 10s parimetros para P r e p a r e d S t a t e m e n t . Por ejemplo, podemos utilizar el metodo s e t S t r i n g ( ) para establecer 10s

218

Programacion de bases de datos con JDBC


parimetros VARCHAR.De un mod0 similar, para establecer el tip0 DATE SQL, podemos utilizar el metodo setDate ( ) . Estos metodos ocupan el lugar del nGmero como primer argumento; entonces, setString(1, tittle) f i j a e l v a l o r d e l p r i m e r ? e n t i t l e . Observe tambikn que el objeto fecha requiere especial tratamiento. Hay cuatro objetos diferentes que podemos utilizar para representar fecha y tiempo. La clase java .uti 1.Date era el Gnico objeto disponible anterior a1 API JDBC. Sin embargo, el paquete j ava .sql introduce tres clases mis:
public class Date extends java.util.Date

Esta clase Date corresponde a1 tipo DATE SQL. Por lo tanto, debemos utilizar java .sql .Date en nuestra programaci6n JDBC para ajustarnos a 10s tipos JDBC:
public class Time extends java.util.Date

Esta clase corresponde a1 tip0 TIME DATE SQL:


public class Timestamp extends java.util.Date

Ninguna de las clases j ava . sql .Date y j ava .sql .Timecaptura laprecisi6n del ~ ~ ~ O T I M E S T A M P SQL. La clase j ava .sql .Timestampcubre estas deficiencias. Los objetos de estampilla de tiempo (timestamp) pueden albergar nanosegundos de TIMESTAMP,ademis de 10s campos estindar de tiempo y fecha. En general, si esti capturando instancias especificas de tiempo, considere utilizar java.sq1.TimeStamp. El API JDBC tambikn ofrece facilidades para invocar procedimientos almacenados. La interfaz j ava .s ql .Cal lableSt atement puede utilizarse para crear instrucciones para ejecutar procedimientos almacenados. Los siguientes metodos de la interfaz j ava .sql .connection crean objetos Callablestatement.
Callablestatement Callablestatement prepareCall(String sql) throws SQLException prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException

En la prictica, un procedimiento almacenado no es apropiado para un entorno JZEE, ya que asocia muy de cerca la aplicaci6n con una base de datos especifica.

Representar tipos SQL en Java


Los tipos de datos SQL y 10s tipos de datos Java no son equivalentes. Mientras que 10s tipos SQL incluyen tipos tales como VARCHAR, NUMBER y TIMESTAMP, y 10s tipos de datos en Java han evolucionado a partir de lenguajes de programaci6n como C y C + +. Esta disparidad entre tipos SQL y tipos de datos Java ha sido tratada con la especificaci6n de tipos SQL genericos y con su representaci6n hacia y desde tipos de datos Java. Los tipos SQL JDBC estin especificados en la clase j ava .sql .Types, como constantes. Existen dos ocasiones en las que requerimos esta representaci6n de informaci6n: a1 establecer 10s parimetros de entrada para instrucciones preparadas (utilizando metodos setxxx ( ) en la interfaz PreparedStatement)y a1 obtener resultados de 10s objetos Resultset (utilizando metodos getXXX ( ) en la interfaz Resultset). En ambos casos, 10s drivers representan 10s tipos en JDBC y 10s tipos Java. La siguiente tabla resume 10s tipos JDBC y su representaci6n en tipos Java, y 10s tipos de datos SQL:

Capitulo 4
TipoJDBC ARRAY BIGINT BINARY Prop6sito Representa el ARRAY tipo S Q L N6mero entero signado de 64 bits Valor binario, pequefio de longitud fija T i p o SQL ARRAY
BIGINT

Tipo Java j ava. s q l .Array long

N o hay correspondencia Consulte su documentacidn de driver boolean j ava. s q l .Blob

BIT BLOB

Valor de un s610 bit (0 6 1) BIT Representa BLOB tip0 ara almacenar RepresentaB~OLEAN tipo S Q L String de caracteres pequefio, de longitud fija BLOB

BOOLEAN CHAR CLOB

BOOLEAN
CHAR

j ava. lang .Boolean


String

Representa CLOB tip0 CLOB S Q L r almacenar objetos gran es de caracteres Representa DATAL INK tipo S Q L Fecha consistente en dia, mes y afio Valores decimales de precisi6n fija Para re resentaci6n adaptaBa de tipos definidos por usuario Niimeros de coma flotante de doble recisi6n con mantisa IS digitos DATAL INK
DATE

java . s q l Clob

DATAL INK DATE DECIMAL DISTINCT

j a v a . n e t . URL

java. s q l .Date
j a v a math .BigDecimal

DECIMAL DISTINCT

User defined

DOUBLE

DOUBLE PRECIS ION

double

BI

FLOTA

NDmeros de coma flotante de doble recisi6n con mantira Be 1 i digitos N6mero entero signado de 32 bits

FLOAT

double

INTEGER JAVA-OBJECT LONGVARBINARY LONGVARCHAR

INTEGER

int Object

Para almacenar objetos Java N o hay correspondencia Valor binario, rande de longitud uariabfe String grande de caracteres de long~tud variable N o hay correspondencia N o hay correspondencia

String

Programacion de bases de datos con JDBC


TipoJDBC
NULL

Prop6sito Para representar valores


NULL

Tipo S Q L
NULL

Tipo Java
null for Java objects, 0 for numeric primitives, and false for Boolean java .math .BigDecimal Object

NUMERIC OTHER

Valores decimales de precisi6n fija Para almacenar/recuperar tipos especificos debase de datos Ndmero de coma flotante de precis611 Gnica con mantisa de 7 digitos NGmero entero signado de 16 bits Tiempo consistente en horas, minutos y segundos Estampilla de tiempo consistente en FECHA, T I EMPO y un campo de nanosegundos NGmero entero no signado de 8 bit Valor binario pequerio de longitud variable String de caracteres pequeiio de longitud vanable

NUMERIC

N o hay correspondencia; destinados a tipos especificos de base de datoddriver


REAL

REAL

float

REF SMALL INT STRUCT TIME TIMESTAMP

NA SMALLINT NA TIME TIMESTAMP

NA short NA java. sql .Time j ava. sql .Timestamp

TINYINT VARB INARY VARCHAR

TINYINT

short

N o hay correspondencia
VARCHAR String

Aunque esta tabla resume todas las posibles representaciones entre SQL y Java, en la prictica el apoyo a estas representaciones varia de driver a driver. Ademis, puesto que no todos 10s vendedores cumplen todos 10s tipos SQL y tambiCn hay varios tipos SQL especificos del vendedor de actualidad, debe comprobar su documentaci6n de base de datos y driver para ajustarse a esta representaci6n. Si la portabilidad de su aplicaci6n es un problema, debe intentar que su SQL se adapte a 10s tipos de datos mas utilizados.

Apoyo a transacciones
En algunas aplicaciones, puede que queramos agrupar una serie de instrucciones que necesiten, todas ellas, ser efectivas o fallar. En tales casos, un grupo de operaciones SQL constituye una unidad de trabajo. La noci6n de la transacci6n es importante para preservar la integridad de las transacciones empresariales que producen mdltiples operaciones SQL. Cuando mdltiples instrucciones son ejecutadas en una dnica

Capitulo 4
transacci611, todas las operaciones pueden ser realizadas (convertidas en permanentes en la base datos) o deshechas (es decir, se deshacen 10s cambios aplicados a la base de datos). El anilisis de esta secci6n se limita a transacciones locales, es decir, transacciones realizadas con una unica base de datos desde un unico cliente. Estudiaremos con detenimiento las transacciones distribuidas mis adelante, en este capitulo. Cuando se crea un objeto c o n n e c t i o n , Cste esti configurado para realizar automiticamente cada transaccibn. Esto significa que cada vez que se ejecuta una instruccibn, se realiza en la base de datos y n o puede ser deshecha. Los siguientes mktodos en la interfaz c o n n e c t i o n son utilizados para demarcar transacciones y bien deshacerlas o realizarlas en la base de datos:
void setAutoCommit(boo1ean autocommit) throws SQLException void commit ( ) throws SQLException void rollback ( ) throws SQLException

Para iniciar una transaccibn, invocamos s e t A u t o C o m m i t ( f a l s e ) . Esto nos otorga el control sobre lo que se realiza y cuindo se realiza. Una llamada a1 mktodo commit ( ) realizari todas las instrucciones emitidas desde la ultima vez que se invoc6 el metodo commit ( ) . Por el contrario, una llamada r o l l b a c k ( ) deshari todos 10s cambios desde la ultimacommit ( ) . Sin embargo, una vez se ha emitido una instruccibn commit, esas transacciones no puede deshacerse con r o l l b a c k . Consideremos un caso prictico de empresa consistente en cuatro pasos, cada uno de 10s cuales conlleva ejecutar una instruccibn SQL y 16gica adicional implementada en la aplicaci6n: crear un pedido, actualizar el inventario y crear un registro de envios. La 16gica de empresa puede requerir que todo sea efectivo o que todo falle. El fracas0 de la creaci6n de un registro de envios puede dictar que no Cree un pedido. En tales casos, 10s efectos de las instrucciones SQL correspondientes a las dos primeras tareas (crear un pedido y actualizar el inventario) deben deshacerse. El siguiente fragment0 de c6digo ilustra esta situacibn:
Connection connection una
=

null;

//

...

Obtener

conexi6n

try

//

I n i c i a r una t r a n s a c c i 6 n c o n n e c t i o n . s e t A u t o C o m m i t ( f a l s e ); statement
=

Statement

connection.createStatement();

//

C r e a r un p e d i d o s t a t e m e n t . e x e c u t e u p d a t e ("INSET INTO ORDERS (ORDER I D , "VALUES(...)");

PRODUCT I D ,

. .. ) "+

//

Actuallzar inventario s t a t e m e n t . e x e c u t e u p d a t e ("UPDATE TABLE INVENTORY " + "SET QUANTITY = QUANTITY - 1 " "WHERE PRODUCT I D = ") ;

...

//
i

C r e a r un r e g i s t r o d e e n v i o s f . [ / / Business l o g i c succeeded ) VALUES ( ) ") ; s t a t e r n e n t . e x e c u t e ("INSERT INTO S H I P RECORD(. c o n n e c t i o n . commit ( ) ; } else { / / F a l l o d e 1 6 g i c a e m p r e s a r i a l . No p u e d e p r o c e d e r c o n e s t e p e d i d o connection. rollback( ) ;

..

. ..

Programacion de bases de datos con JDBC


I
}

1
1

catch (SQLException e) { / / Manejar excepciones aqui finally { / / Cerrar instrucci6n y cortexi6n

En este fragmento, una vez invocado el metodo r o l l b a c k ( ) , la base de datos restaura las tablas PEDIDOS e INVENTARIO a su estado anterior. commit ( ) convierte en permanentes 10s cambios efectuados por las instrucciones INSERT y UPDATE. Analizaremos las transacciones con mis detalle mis adelante en este capitulo.

Puntos de salvaguardia
El API JDBC 3.0 introduce puntos de salvaguardia. U n punto de salvaguardia es similar a un marcador temporal fijado en una posici6n especifica durante una serie de operaciones de bases de datos en una transacci6n. U n punto de salvaguardia le permite realizar o deshacer transacciones de forma parcial. Para comprender la noci6n de punto de salvaguardia, considere utilizar un procesador de textos para editar un archivo. Durante el proceso de edicibn, puede guardar el documento varias veces. Cada operaci6n de guardar es como establecer un nuevo punto. DespuCs de guardar puede volver a la versi6n guardada anteriormente negando simplemente todas las ediciones y reabriendo el mismo archivo. De un modo similar, el mecanismo j a v a .s q l .S a v e p o i n t le permite realizadabortar operaciones en varios puntos de salvaguardia. Considere la siguiente secuencia de operaciones de base de datos:
Connection connection
=

null;

//

...

Obtener una conexi6n

try i / / Iniciar una transacci6n connection.setAutoCommit(fa1se);

.. .
//

//

Ejecutar el primer grupo d e operaciones de base d e datos Ejecutar el segundo grupo de operaciones de base d e datos Ejecutar el tercer grupo de operaciones de base de datos

. ..

...
)
}
1

//

catch (SQLException e) { / / Manejar excepciones aqui finally { / / Cerrar instrucci6n y conexi6n

Supongamos que 10s tres grupos de operaciones estin 16gicamente relacionadas. Por ejemplo, si hubiera un fallo durante la ejecuci6n del segundo grupo de operaciones, no habria modo alguno de deshacer s61o el segundo grupo y ejecutar otro grupo distinto de operaciones correctivas. Los mCtodos commit ( ) y r o l l b a c k ( ) se aplican a 10s tres grupos de operaciones en su conjunto. Puede superar esta hnitaci6n con 10s puntos de salvaguardia. Considere c6mo puede implementarse la situaci6n anterior utilizando puntos de salvaguardia:
Connection connection
=

null;

Capitulo 4

//

...

Obtener

una

conexihn

try

/ / I n i c i a r una t r a n s a c c i 6 n connectior~.setAutoCornrnit(fa1se);

... ...
//

//

Elecutar

el

prlrner

grupo d e operaciones

de

base

de datos

Savepoint s p l Ejecutar e l

conr~ection.setSavepoir~ (" t F i r s t Batch") ; segundo grupo d e o p e r a c i o n e s d e b a s e d e d a t o s

/ / Si es necesario deshacer datos i f (...) {


)

el

segundo grupo d e

operaciones

de base

de

connection.rollback(sp1); / / E j e c u t a r operaciorles c o r r e c t i v a s s i procede


else

connection.releaseSavepoir~t(spl);
1

...
]

//

Ejecutar

el

sequrldo

grupo

de

operaciones

de base de datos

1
1

c a t c h (SQLExceptiori e ) [ / / Handle e x c e p t i o n s h e r e finally { / / Cerrar instrucci6n y conexitn

En este caso, despuis de ejecutar el primer lote de operaciones fijam.os un punto de salvaguardia con un determinado nombre (spl). Observe que el nombre es opcional y es utilizado por 10s drivers para identificar un punto de salvaguardia. Cuando no se designa un nombre, 10s drivers utilizan un I D generado internamente en lugar del nombre. Despuks de fijar este punto de salvaguardia, posteriormente, podemos liberar el punto de salvaguardia, o deshacer todas las operaciones ejecutadas despuks de establecer el punto de salvaguardia. En el c6digo anterior, la llamada rollback (spl)deshace el segundo grupo de operaciones de base de datos sin afectar a1 primer grupo de operaciones. Sin embargo, una vez ha liberado un punto de salvaguardia, cualquier llamada rollback ( ) posterior deshace todas las operaciones incluido las ejecutadas antes de establecer el punto de salvaguardia. Puede fijar mas de un punto de salvaguardia durante una determinada transacci6n. Sin embargo, cualquier acci6n de deshacer ejecutada en un punto de salvaguardia invalida todos 10s puntos de salvaguardia fijados despuis. Por ejemplo, si establece tres puntos de salvaguardia spl,sp2 y sp3 (fijados en el mismo orden) e invoca rollback (sp2) ,el tercer punto de salvaguardia, sp3,queda invalidado. Una vez establecido un punto de salvaguardia, puede liberarlo mas tarde utilizando el mktodo releasesavepoint ( ) en el objeto java. sql . ~ o n n e c t i o n u t i l i z a d o p a r a f i j a r e l p u n t o d e salvaguardia. Una vez liberado el punto de salvaguardia, puede utilizarlo para deshacer. Sin embargo, no puede cambiar la ubicaci6n de un punto de salvaguardia una vez kste es establecido durante una transacci6n. Fijese en que la caracteristica de punto de salvaguardia es relativamente nueva en el API JDBC y, por ello, en el momento de escribir este capitulo, n o todos 10s drivers JDBC se ajustan a esta caracteristica. Puede determinar si su base de datosldriver cumple este requisito, utilizando el siguiente mitodo en
java.sq1.DatabaseMetaData:
boolean supportsSavepoints() throws SQLException

Programacion de bases de datos con JDBC


Aunque el punto de salvaguardia es nueva en el API JDBC, bases de datos como Microsoft SQL Server y Oracle se ajustan a esta caracteristica.

Listas de resultados desplazables y actualizables


Antes de JDBC 2.1, un objeto Resultset (lista de resultados) creado a1 ejecutar una instrucci6n era, por defecto, desplazable hicamente hacia adelante. Es decir, s610 podiamos recorrer la lista de resultados utilizando el mktodo next ( ) . next ( ) devuelve false cuando se llega a1 ultimo registro y no se pueden recuperar mis detalles. El API JDBC 2.1 (incluido en J2EE 1.2 y versiones posteriores) ofrece medios mis flexibles para acceder t Estos avances estin clasificados del siguiente modo: a 10s resultados desde objetos ~ e s u l set.
O Listas de resultados desplazables

Los objetos Resultset JDBC 2.1 son desplazables. Las listas de resultados desplazables tienen la capacidad de mover el cursor hacia detris y tambikn permiten una libertad absoluta de ubicaci6n del cursor en una fila determinada de la lista de resultados. Sensibilidad de desplazamiento El API JDBC 2.1 tambikn especifica listas de resultados sensibles a1 desplazarniento e insensibles a1 desplazamiento. Una lista de resultados insensible a1 desplazamiento representa una instantinea estitica de 10s resultados a1 realizar la consulta. Por otro lado, una lista de resultados sensible a1 desplazamiento es sensible a 10s cambios efectuados a 10s datos despuks de que la consulta haya sido ejecutada, proporcionando asi una visi6n dinamica de 10s datos a medida que kstos cambian. Listas de resultados actualizables Por defecto, las listas de resultados son de s61o lectura. Es decir, 10s contenidos de la lista de resultados s610 pueden ser leidos y no pueden ser alterados. El API JDBC 2.1 introduce las listas de resultados actualizables. Cuando una lista de resultados es actualizada, la operaci6n de actualizaci6n tambikn actualiza 10s datos originales correspondientes a la lista de resultados. java.sql.ResultSet cuenta con mktodos adicionales que cumplen estas caracteristicas, que serin analizadas en 10s siguientes subapartados.

Listas de resultados desplazables La interfaz j ava . sql .~ e s u l Set t especifica tres tipos de listas de resultados:
TYPE-FORWARD-ONLY. Una lista de resultados de este tip0 s61o se adapta a1 desplazamiento hacia delante. TYPE-SCROLL-INSENS ITIVE.Unalista de resultados de este tipo se desplaza en ambas direcciones.
TYPE-SCROLL-SENS ITIVE.Una lista de resultados de este tip0 es sensible a actualizaciones realizadas a 10s datos despuks de poblar la lista de resultados. Por ejemplo, si su consulta devuelve 10 filas y si otra aplicaci6n elimina dos de las filas, su lista de resultados s610 tendri 8 filas. Lo mismo ocurre para inserciones/actualizaciones.

Antes de utilizar 10s mktodos de la interfaz j ava sql .~ e s u l set t para desplazarse por 10s resultados, debemos asegurarnos que el driver JDBC se ajusta a estas caracteristicas. La interfaz j ava sql .DatabaseMetadata proporcionavarios mktodos para descubrir la capacidad del driver de base de datos.

Capitulo 4
Para saber qu6 tipos de resultados se adaptan utilice supportsResult SetType ( ) . Por ejernplo, el siguiente fragment0 de c6digo debe informarnos sobre el apoyo del driver a estos tipos:
public void testScrollable() throws SQLExceptior~ [ boolean supports; DatabaseMetaData r n d supports
= =

conr~ection.getMetaData ( )

md.supportsResultSetType(Resu1tSet.TYPE FORWARD ONLY);

if(supports) i System.out..printlrl ("TYPE FORWARD ONLY - Supports") ; I else { System. out .println ("TYPE FORWARD ONLY - Does not support" )
1

supports

md.supportsResultSetType(Resu1tSet.TYPE SCROLL INSENSITIVE);

if (supports) { System.out .println ("TYPE SCROLL INSENSITIVE - Supports") ; 1 else { System.out.println( "TYPE SCROLL INSENSITIVE - Does not support");
I

supports

md.supportsResultSetType(Resu1tSet.TYPE

SCROLL SENSITIVE);

if(supports) { System. out .println ("TYPE SCROLL SENSITIVE - Supports") ; 1 else { System. out .println ("TYPE SCROLL SENSITIVE - Does r ~ o t support" )

Para listas de resultados sensibles a1 desplazamiento, 10s siguiente rnetodos de j ava . sql .DatabaseMetadata devuelveninformacion sobre elnivel de sensibilidad:
public boolean othersUpdatesAreVisible(int type) throws SQLException

Este metodo devuelve true si 10s carnbios efectuados por otras transacciones son visibles para una lista de resultados sensibles a1 d e ~ ~ l a z a m i e n t o .
public boolean othersDeletesAreVisible(int type) throws SQLException

othersDe let eAreVis ible ( ) devuelve t rue si las elirninaciones realizadas por otras transacciones son visibles en una lista de resultados sensible a1 desplazarniento.
public boolean othersInsertsAreVisible(int type) throws SQLException

others InsertAreVisible ( ) devuelve t rue si las inserciones efectuadas por otras transacciones son visibles en una lista de resultados sensible a1 desplazamiento.

De un modo similar, la interfaz j ava .sql .DatabaseMetadata especifica 10s mitodos ownUpdateAreVisible ( ) ,ownDeleteAreVisible ( ) y o w n ~ n s e r t s ~ r e ~ i s i b () lparasabersi e 10s cambios efectuados a 10s resultados son visibles en esta lista de resultados. La interfaz j ava .sql .Result Set se ajusta a 10s siguientes mitodos para desplazar las listas de resultados. Estos metodos estin agrupados s e g h su uso.

Programacion de bases de datos con J DBC


M6todos relacionados con la posicion del cursor
public boolean public boolean isBeforefirst() throws SQLException i s A f t e r L a s t 0 throws SQLException

i s B e f o r e F i r s t ( ) devuelve t r u e si la posici6n del cursor es anterior a la primera fila de la lista de resultados. i s A f t e r L a s t ( ) devuelve t r u e si la posici6n del cursor es posterior a la dtima fila de la lista de resultados.
public boolean public boolean i s f i r s t o throws SQLException islast ( ) throws SQLException
()

i s F i r s t ( ) devuelve t r u e si el cursor esti situado en laprimera fila de la lista de resultados. i s L a s t devuelve t r u e si el cursor esti en la Gltirna fila de la lista de resultados.
public v o i d b e f o r e f i r s t o throws SQLException public v o i d afterlast 0 throws SQLException

Estos dos mitodos devuelven t r u e si la posici6n del cursor es anterior a la primera fila o posterior a la 6ltirna fila de la lista de resultados respectivamente.
Metodos para desplazamiento
public boolean public boolean first ( ) throws SQLException last 0 throws SQLException

Estos mCtodos desplazan el cursor hasta la primera y Gltima fila de la lista de resultados respectivamente.
public boolean absolute(int row) throws java.sq1.SQLException

a b s o l u t e ( ) desplaza el cursor hasta la fila especificada en la lista de resultados. El argumento de fila puede ser positivo o negativo. U n argumento negativo desplaza el cursor hacia atris, mientras que un argumento positivo desplaza el cursor hacia delante.
public boolean relative(int rows) throws SQLException

Este mCtodo desplaza el cursor el numero de filas especificado relativo a la posici6n actual del cursor. Si el argument0 es positivo, este mCtodo desplaza el cursor hacia delante el numero de filas especificado. Si es negativo, este mitodo desplaza el cursor hacia atris el n h n e r o de filas especificado. Si el numero especificado (positivo o negativo) es mayor que las filas disponibles (hacia delante o hacia atris), este mCtodo sitGa el cursor en la prirnera o en la ultima fila de la lista de resultados. Este mCtodo no deberia ser invocado cuando la posici6n del cursor no es vilida. Por ejemplo, despues de invocar n e x t ( ) recursivamente hasta que n e x t ( ) devuelva false (lo que significa el final de la lista de resultados), no debemos invocar r e l a t i v e ( ) ,puesto que la posici6n actual esti fuera de la lista de resultados. Antes de invocar r e l a t i v e ( ) , debemos levar el cursor hasta una posici6n vilida utilizando 10s rnCtodos
absolute (), f i r s t ( ) o l a s t ().
public boolean previous() throws SQLException

p r e v i o u s ( ) desplaza el cursor hasta la fila anterior, relativa a la posici6n actual. A diferencia del mCtodo r e l a t i v e ( ) , este metodo puede ser invocado incluso cuando no existe una fila anterior. Por ejemplo, despuks de invocar nex t ( ) recursivamente hasta que devuelva f a l s e , podemos i n v o c a r p r e v i o u s ( )

para llevar el cursor hasta la ultima fila.

Direction y tamaiio de toma


public void setFetchDirection(int direction) throws SQLException

Capitulo 4
Este rnktodo nos perrnite establecer una direccidn de torna. La interfaz j a v a . sql .ResultSet especifica tres constantes de direction de torna:Resul tS et .FETCH-UNKNOWN,Resul tS et FETCH-FORWARD,y Result Set.FETCH-REVERSE.Estos tipos indican la direcci6n de torna actual para 10s resultados.

Esta lista de resultados puede optirnizar internarnente las estructuras de resultados para el tip0 de desplazarniento especificado.
public int getFetchDirection0 throws SQLException

Este rnktodo devuelve la actual direcci6n de torna.


public void setFetchSize(int rows) throws SQLException

Este rnktodo nos da una indicaci6n del driver JDBC en cuanto a1 nurnero de filas que deberian ser tornadas de la base de datos. Observe que, cuando el tarnaho de toma esti fijado en 1, la lista de resultados puede tornar 10s datos de la base de datos siernpre que invoquernos next ( ) . Fijando un tarnaho de torna mayor, podrernos utilizar rnejores tomas optirnizadas.
public int getFetchSize0 throws SQLException

Este metodo devuelve el tarnaho de torna actual. Observe que una configuraci6n inapropiada de direcci6n y tarnafio de torna puede afectar a1 rendirniento. A1 establecer estos valores, debernos considerar el nurnero de filas que esperarnos obtener en la lista de resultados y su supuesto uso. Los siguientes ejernplo ilustran estos rnktodos. Fijese en que 10s resultados de este c6digo dependen del apoyo del driver:
public void queryByScrollableResultSet() throws SQLException cor~r~ection.setAutoCommit (false) ;
[

Statement statement = connection.createStatement(Resu1tSet.TYPE SCROLL INSENSITIVE, ResultSet.CONCUR READ ONLY); ResultSet stroller= statement .executeQuery("SELECT CATALOG.TITLE, " + "CATALOG. LEAD ACTOR, " + "CATALOG.LEAD ACTRESS, " + "CATALOG.TYPE, " + "CATALOG.RELEASE-DATE FROM CATALOG");

Para poner en prictica 10s rnktodos indicados para listas de resultados desplazables, Cree prirnero una lista de resultados. El fragment0 anterior puebla un objeto scroller de lista de resultados:
int type = scroller.getType ( ) ; switch(type) [ case ResultSet .TY PE FORWARD ONLY : System.out.prir~tln("Type = TYPE FORWARD ONLY"); break; case ResultSet.TYPE SCROLL SENSITIVE : Syst'em.out.println ("Type = TYPE SCROLL SENSITIVE") ; break; case ResultSet.TYPE SCROLL INSENSITIVE : System.out .println ["Type = TYPE SCROLL INSENSITIVE") ; break; 1

Programacion de bases de datos con JDBC


System.out.println ("Currer1t fetch size: " t scroller.getFetchSize i ) ) ; scroller.setFetchSize(2); System.out .prir~tlr~("Fetch size reset to: " t scroller.getFetchSize())

El c6digo anterior indica el nivel de apoyo para listas de resultados desplazables y nos permite cambiar el tamafio de toma. Del mismo modo, podemos conocer el nivel de apoyo para concurrencia. El siguiente c6digo desplaza la lista de resultados tanto hacia delante como hacia atris. Como ya hemos mencionado, 10s resultados de este c6digo dependen del apoyo del driver. En el momento de escribir este libro, Cloudscape 3.6.4 se adapta a listas de resultados de solo lectura pero a no proporciona listas de resultados actualizables:
int count = 0; System.out .prir~tlr~("Scrolling forward from the beginning . . . " ) ; while(scroller.next ( ) ) { System.out .println (count++ + " : " t scroller.getString ("TITIIEE') t ", " t scroller.getString("TYPE") ) ; scroller.first ( ) ; System.out .println ("Stroller moved

to first. " )

stroller. absolute Icourlt/2); System.out.prir~tln("Scr011er moved to " t count/2); System.out.println("Scr011ing forward . . . " ) ; while(scroller.next~)) { System.out .prlntln(" " t scroller,getString("TITLE") t t scroller.getString ("TYPE")) ;
)

",

"

scroller.first(); System.out .println("Scro11er moved

to first.");

int fetchDirection = scroller.getFetchDirection(); switch(fetchDirection) [ case ResultSet.FETCH UNKNOWN: System.out .println ("Current fetch direction: FETCH UNKNOWN") ; break; case Resultset. FETCH FORWARD: System.out .println ("Current fetch direction: FETCH FORWARD" ) ; break; case ResultSet.FETCH REVERSE: System.out .println ("Current fetch direction: FETCH REVERSE") ; break; 1 scroller.setFetchDirectior~(Resu1tSet.FETCH REVERSE); System.out.println("Fetch direction set to FETCH REVERSE"); scroller.absolute(-count/3); Systern.out .println("Scroller moved to " + (-count/3)) ; Systern.out.println("Scr011ing forward . . . " ) ; while(scroller.next~)) { System.out.println ( " " + scroller.getString("T1TLE") scroller.getString("TYPE")) ;

+ ", "

scroller.previous0; scroller.relative(-2); System.out.println("Scr011er moved by -2 rows relative to the current" "position");

Capitulo 4
System.out .println ("Scrollir~g forward . . . " ); while (scroller.next ( ) ) { System. out .println ( " " + scroller.getString("T1TLE") + scroller.getString ("TYPE")) ; 1

", "

Listas de resultados actualizables


Por defecto, las listas de resultados son de s61o lectura. Es decir, 10s contenidos de la lista de resultados son de s6l0 lectura y no pueden ser alterados. El API JDBC 2.1 tambikn introduce listas de resultados actualizables. Cuando una lista de resultados es actualizada, la operaci6n de actualizaci6n tambikn actualiza 10s datos correspondientes a la lista de resultados. La interfaz j ava . sql .Resultset especifica dos constantes para indicar si la lista de resultados es de s610 lectura o es actualizable:

o CONCUR-READ-ONLY: Utilizando este tip0 de lista de resultado no podemos utilizar ninguno de


10s mktodos analizados a continuaci6n para insertar, actualizar o eliminar filas.

o CONCUR-UPDATABLE:C o n esta constante, podemos insertar, actualizar o eliminar filas en la lista


de resultados. Estos tipos son denominados tipos de concurrencia. Podemos conocer el tip0 de concurrencia de una lista de resultados invocando el mktodo getconcurrency ( ) en la lista de resultados. La interfaz j ava .s ql .Results et especifica el siguiente grupo de mktodos para actualizar resultados.
Adualizar una fila

El siguiente grupo de mktodos updateXXX ( ) esti destinado a actualizar 10s elementos de la fila actual en la lista de resultados:
updateAsciiStream() updateBlob ( ) updateBytes ( ) updateDate ( ) updateInt ( ) updateOb ject ( ) updateshort ( ) updateTimestamp
()

UpdateBigDecimal UpdateBoolean ( )

()

Updatecharacterstream() UpdateDouble ( ) UpdateLong ( ) UpdateRef ( ) Updatestring ( )

Estos mktodos requieren el nombre de columna (como un string) o el indice de columna como primer argument0 y un objeto de tip0 XXX. Por ejemplo, hay dos variantes de mktodos updateTimestamp ( ) :
public void updateTimestamp (int columnIndex, Timestamp x) public void updateTimestamp(String columnName, Timestamp x )

Programacion de bases de datos con JDBC


Despues de invocar estos rnitodos, debernos invocar el metodo u p d a t e R o w ( ) para actualizar 10s carnbios. Alternativarnente, podernos invocar el rnetodo c a n c e l R o w U p d a t e s ( ) para cancelar todas las actualizaciones realizadas hasta el rnornento. El rnktodo r o w s u p d a t e ( ) nos perrnite saber si la fila actual ha sido actualizada. El valor devuelto depende de si el resultado puede detectar o no actualizaciones.

Eliminar una fila


Podernos utilizar el metodo d e l e t eRow ( ) para elirninar la fila actual de la lista de resultados asi corno de la base de datos subyacente. El rnktodo r o w D e l e t e d ( ) indica si una fila ha sido elirninada utilizando la lista de resultados. Observe que una fila elirninada puede dejar un vacio visible en una lista de resultados. el rnetodo r o w D e l e t e d ( ) puede utilizarse para detectar estos vacios. A1 desplazar una lista de resultados que pueda tener filas elirninadas, puede invocar este metodo para detectar estas filas elirninadas.

lnsertar una fila


Para insertar una fila en la lista de resultados y e n la base de datos subyacente, debernos prirnero utilizar m o v e T o I n s e r t R o w ( ) y despues uno o rnis rnetodos d e u p d a t e x x x ( ) . Una llarnada a1 rnetodo m o v e T o I n s e r t R o w ( ) desplaza el cursor hasta la fila insertar. La fila insertar es un bhfer especial asociado a una lista de resultados actualizable. Despues de mover el cursor hasta esta fila, podernos utilizar 10s rnktodos updateXXX ( ) habituales para fijar 10s elernentos de esta fila. A1 final de estas llarnadas, debe invocar i n s e r t R o w ( ) para insertar finalrnente la fila en una base de datos y para lirnpiar la fila bGfer.

Actualizaciones de lotes (batch)


Adernis de las listas de resultados desplazables, el API JDBC 2.1 especifica apoyo para actualizaciones de lotes. Esta caracteristica perrnite multiples instrucciones de actualizaci6n (INSERT, UPDATE o DELETE) en una unica solicitud a la base de datos. Procesar en lotes gran nurnero de resultados puede tener corno resultado irnportantes avances de rendirniento. Por ejernplo, podernos volver a rnodificar la tabla para la base de datos de Peliculas pero esta vez podernos ejecutar todas las instrucciones INSERT en un unico lote. Tarnbikn podernos utilizar instrucciones preparadas en un lote. A1 cornparar con i n s e r t D a t a ( ) en el ejernplo, la Gnica diferencia en esta irnplernentaci6n son las llarnadas a1 rnktodo a d d B a t c h ( ) y el rnetodo e x e c u t e B a t c h ( ) en la instrucci6n para la actualizaci6n de lotes:
pub1 ic void insertBatchData i I throws SQLException, IOException ( Buf feredReader br = new BufferedReader(r1ew FileReader ("catalog. txt") ) ; statement = connection. createstatement ( ) ; try 1 do 1 title = br.readLine(); if (title == null ) break; 1eadActor = br. readline ( ) ; leadActress = br. readline ( ) ; type = br. readline ( ) ; dateOfRelease
=

br. readline ( ) ;
=

String sqlstring

"INSERT INTO CATALOG VALUES('" 1eadActor + "',"' t 1eadActress type + "',"' + dateOfRelease t

+ title + + "',"' t
"')";

',"I

Capitulo 4

statement.addBatch(sqlStrir~g); while (br. readline ( ) ! = null);

statement.executeBatch(); catch (EOFExceptinn e) {

I I

finally [ statement.close0; br. close ( ) ;

iPor quk esto produce un rnejor rendirniento? En lugar de ejecutar una serie de instrucciones, estarnos realizando todas las actualizaciones en una unica instruccidn. Esto reduce el sobregasto del servidor de base de datos, puesto que, de no ser asi, hubikramos tenido que destinar y rnantener recursos /cursores, etc.) para cada instrucci6n.

El paquete javaxsql
El paquete j a v a x .sql esti basado desde el punto de vista de la arquitectura en el paradigrna de prograrnacidn cliente-servidor. Corno ya hernos analizado en las secciones anteriores, la tipica prograrnacidn JDBC incluye 10s siguientes pasos:
O 0 0

Cargar el driver de la base de datos (utilizando el nornbre de clase del driver) Obtener una conexi6n (utilizando el URL JDBC para la base de datos) Crear y ejecutar instrucciones

3 Utilizar las listas de resultados para navegar por 10s resultados


0

Cerrar la conexidn

Si esti farniliarizado con 61, reconoceri este rnodelo por ser exactarnente igual a ODBC. Este rnodelo de prograrnaci6n es apropiado para clientes portitiles con conexiones de larga duracidn y transacciones de bases de datos localizadas. En tales aplicaciones, uno o rnis clientes portitiles (construidos utilizando Visual Basic, PowerBuilder, etc.) conectan a una base de datos central y realizan varias visitas a la base de datos para implernentar diversos casos pricticos de ernpresa. Sin ernbargo, este rnodelo no es apropiado para aplicaciones distribuidas de base Web, principalrnente por las siguientes razones:
0

Gesti6n de conexiones Existen dos lirnitaciones a1 utilizar j a v a . s q l .D r i v e r M a n a g e r para la gestidn de conexiones. Cada vez que un cliente requiere una conexidn, este API intenta obtener una nueva conexi6n. Corno verernos rnis adelante en este capitulo, este estilo de gestidn de conexidn no resulta eficiente para aplicaciones distribuidas con centro en Internet. En segund.0 lugar, j a v a . s q l .D r i v e r M a n a g e r no aisla las aplicaciones cliente de clases especificas de driver. Apoyo de transacciones Adernis, el paquete j a v a .sql no tiene apoyo de arquitectura para transacciones distribuidas. Corno verernos rnis adelante, el apoyo a transacciones distribuidas es esencial para construir aplicaciones de empresa reajustables y resistentes a 10s fallos.

El paquete j a v a x .sql ofrece las siguientes caracteristicas para tratar 10s puntos anteriores:

Programacion de bases de datos con JDBC


0

Bfisqueda de base J N D I para acceder a las bases de datos via nombres 16gicos
En lugar de que cada cliente intente cargar las clases de driver en sus miquinas virtuales respectivas, utilizar las biisquedas de base J N D I nos permite acceder a 10s recursos de base de datos utilizando nombres 16gicos asignados a estos recursos.

Reserva de conexiones

El paquete j a v a x . s ql especifica una capa intermedia adicional para implementar la reserva de conexiones. Es decir, la responsabilidad para la reserva de conexiones es trasladada desde desarrolladores de aplicaciones a vendedores-servidores de drivers y aplicaciones. El paquete j a v a x sql especifica un marco para apoyar las transacciones distribuidas de forma transparente bajo el paquete j ava. sql. C o n este marco de trabajo, el apoyo a transacciones distribuidas puede ser activado en un entorno J2EE con una minima configuraci6n.

m Transacciones distribuidas

m Conjunto de filas (Rowset)


U n objeto ow set es un objeto adaptado a JavaBeans que encapsula listas de resultados debase de datos e informaci6n de acceso. U n conjunto de filas (rowset) puede ser conectado o desconectado. Observe que una lista de resultados debe permanecer conectada a una base de datos. Es decir, la conexi6n esti abierta mientras existe el objeto. Sin embargo, el conjunto de filas nos permite encapsular un conjunto de filas, sin mantener necesariamente una conexi6n. El conjunto de filas tambikn nos permite actualizar 10s datos y propagar 10s cambios de vuelta a la base de datos subyacente. Estas funciones simplifican la programaci6n JDBC en un paradigma distribuido como es J2EE. Exceptuando el uso de un conjunto de filas en lugar de una lista de resultados, utilizando JNDI, 10s servicios de transacciones distribuidas v de reserva de conexiones s61o reauieren cambios minimos en las aplicaciones cliente. Estos servicios son ahora responsabilidad del driver JDBC y del servidor de apkaci6n J2EE. Los vendedores de driver JDBC y 10s vendedores de servidor de aplicaciones J2EE pueden hacer uso de las capas intermedias en este API para construir estos servicios. La mayor parte de clases e interfaces de este paquete estin pensada para que 10s vendedores de servidor de aplicaciones y de drivers de base de datos las implementen en sus productos. El n6mero de clases e interfaces que necesitaremos para desarrollar aplicaciones de cliente es reducido. Por lo tanto, en el resto de este capitulo, nuestro punto de atenci6n se centrari en el anilisis de estos servicios y no en c6mo utilizarlos para desarrollar aplicaciones de cliente. Siempre que sea aplicable, proporcionaremos fragmentos de c6digo para ilustrar 10s aspectos de programaci6n. Para poner a prueba 10s conceptos analizados en este capitdo, debe tener la ultima Implementaci6n de Referencia J2EE de Sun Microsystems (disponible para su descarga en http://java.sun.conl/j2ee/) o un servidor comercial de aplicaci6n JZEE. Tambikn necesitari 10s drivers que se ajustan a kstos. Debe tener en cuenta, sin embargo, que no todos 10s vendedores de servidor de drivers y aplicaciones se ajustan en la actualidad a todas las funciones de este API. N o obstante, es importante comprender c6mo pueden ser disefiados estos servicios. Si desea una lista actualizada de vendedores que cumplan estas caracteristicas, dirijase a la base de datos del driver en http://industry.java.sun.co~products/jdbc/drivers/. En esta seccibn, analizaremos 10s siguientes puntos:
0

Fuentes de datos: c6mo funciona este mecanismo y c6mo simplifica el acceso a la base de datos. Reserva de conexiones: instalaciones para la reserva de conexiones en el paquete j a v a x .sql.

0 Transacciones distribuidas: antecedentes y conceptos asociados alas transacciones distribuidas.

Veremos c6mo el API JDBC, junto con el API de Transacci6n Java, gestiona transacciones distribuidas.
0

El conjunto de filas (rowset).

Capitulo 4

El paquete j avax sql proporciona un sustituto para la clase estitica j ava sql .DriverManager, aunque todavia esti incluida para compatibilidad retroactiva. El repuesto es la interfaz j avax .sql DataSource como medio primario de crear conexiones de base de datos. Con respecto de la programaci6n,los siguientes son 10s factores destacables:

En lugar de cargar explicitamente las clases del gestor de drivers en el period0 de ejecucion de la aplicacion cliente, utilizamos una btisqueda centralizada de servicio JNDI para obtener un objeto java.sql.DataSource. En h g a r de utilizar la clase java sql .DriverManager,utilizarnos la interfaz javax . sql DataSource,que ofrece funciones similares para obtener conexiones debase de datos.

Este enfoque aisla las aplicaciones cliente de la re~~onsabilidad inicializacion del driver de base de datos. Esto significa que las aplicaciones cliente no necesitan conocer las clases de driver de base de datos y el URL de base de datos. Estas tareas pasan ahora a ser re~~onsabilidad del administrador de servidor que configura las fuentes de datos. Como veremos mis adelante en este capitulo, esta separation tambikn permite a servicios adicionales como reserva de conexiones y apoyo a transacciones ser activados sin afectar a aplicaciones adicionales.

La interfaz javax.sql.DataSource
La interfaz j avax sql .DataSource es una factoria para crear conexiones de base de datos. Una factoria es un modelo utilizado para crear instancias de clases sin tener que instanciar directamente clases de implementation. La interfaz j avax .sql DataSource proporciona 10s siguientes mktodos:

Comencemos por getconnect ion ( ) .

El metodo getConnection0
public Connection getconnection0 throws SQLException public Connection getConnection(String username, String password) throws SQLException

Estos mktodos devuelven una conexign a una fuente de datos. Observe que el tip0 devuelto de este mktodo es un objeto connection.Este es el mismo que es devuelto de la interfaz java .sql .DriverManager. Observe que cuando recuperamos un objetoconnection de la clase java sql .DriverManager,esprobable que el objeto~onnectionencapsuledirectamenteuna conexion de red. Sin embargo, como veremos mis adelante en este capitulo, el objeto connection no

Programacion de bases de datos con JDBC


necesita encapsular directamente una conexi6n fisica de base de datos. En su lugar, el objeto c o n n e c t i o n puede delegar la mayoria de sus operaciones en otra capa que pueda implementar la reserva de conexiones y las transacciones distribuidas.

El metodo getLoginTimeout()
public int getLoginTimeout
()

throws SQLException

Este metodo devuelve el intervalo de tiempo en segundos que representa el tiempo que esperari la fuente de datos mientras intenta obtener una conexi6n a la base de datos. El plazo limite por defecto de registro es especifico del driver/base de datos.

El metodo setLoginTimeout()
public void setLoginTimeout(int seconds) throws SQLException

Este metodo especifica el intervalo de tiempo en segundos que la fuente de datos debe esperar mientras intenta obtener una conexi6n a la base de datos. Observe que el driver JDBC tendri un intervalo de tiempo por defecto.

El metodo getlogwriter()
public Printwriter getlogwriter0 throws SQLException

Este mCtodo devuelve elactualobjeto j a v a . i o . p r i n t w r i t e r a1 que el o b j e t o ~ a t a s o u r c e escribe 10s mensajes de registro. Observe que por defecto, a menos que se establezca un objeto P r i n t w r i t e r utilizando el metodo s e t L o g W r i t e r , el registro es desactivado y el metodo devolveri n u 1 1.

El metodo setlogwriter()
public void setLogWriter(L0gWriter out) throws SQLException

Este metodo establece un j a v a . i o L o g w r i t e r con intenciones de registro. Por ejemplo, podemos crear un objeto P r i n t w r i t e r con S y s t e m . o u t como flujo de salida y configurarlo como registro, como se muestra a continuaci6n:
Prir~tWriter logwriter
=

new Printwriter (Systern.out);

/ / datasource es el objeto Datasource datasource.setLogWriter(1ogWriter);

Observe que todos estos mCtodos lanzan una excepci6n j a v a .s q l S L Q E x c e p t i o n . Como podemos ver en la lista de mktodos anterior, esta interfaz es muy sencilla y su principal responsabilidad es crear conexiones. Sin embargo, hay dos cuestiones referentes a este uso: iQuien crea un objeto implementando esta interfaz? i C 6 m o pueden 10s clientes de aplicacidn obtener esta instancia, de mod0 que las aplicaciones puedan obtener conexiones? El siguiente subapartado responde a estas preguntas.

JNDI y fuentes de datos


Una fuente de datos es considerada un recurso de red, recuperado de un servicio JNDI. En un servicio J N D I , las aplicaciones pueden asociar objetos a nombres. Otras aplicaciones pueden recuperar estos objetos utilizando estos nombres. Ambas aplicaciones que asocian objetos a nombres en el servicio J N D I y las aplicaciones que buscan estos nombres en el servicio J N D I pueden ser remotas. El API JDBC permite a 10s vendedores de servidor de aplicaciones y a 10s vendedores de drivers construir recursos de base de datos basados en este enfoque. El siguiente diagrama ofrece un anilisis de este enfoque:

2 . Buscar objeto DataSource


I

S~WICIOJNDI

1 .Asoc~arobjeto DataSource . --

lnsfraestructura de servdor de

1
I

Apl~cac~on JDBC

3 Obtener conexlon de DataSource -

Fuente de

datosl DataSource
-

Conex16n

Drwer J D B ~

-+

de datos

para acceso a datos

Este diagrama muestra de forma esquemitica c6mo 10s objetos que implementan la interfaz j a v a x sql .D a t a S o u r c e estin disponibles en un servicio J N D I y c6mo 10s clientes de aplicaci6n JDBC pueden buscar estos objetos, y crear objetos c o n n e c t i o n .

Ademis de 10s clientes de aplicacion JDBC y 10s recursos de base de datos, esta figura muestra dos componentes mis: un servicio J N D I y una aplicaci6n (normalmente, un contenedor J2EE) que asocia 10s objetos j a v a x sql .D a t a S o u r c e en el servicio JNDI. Un servicio J N D I es un proveedor del API JDBC. Normalmente, la aplicaci6n que asocia 10s objetos j a v a x . sql D a t a s o u r c e en el servicio J N D I es un servidor de aplicacion (que implementa posiblemente todos 10s servicios J2EE).

Los siguientes puntos son las responsabilidades de cada uno de 10s bloques de la figura anterior:

O El servidor de driver o de aplicaci6n ("infraestructura" en la figura anterior) implementa la interfaz javax.sql.DataSource.

u El servidor de a~licacibn crea una instancia del obieto imdementando la interfaz


javax.sql.DataSource y la asocia a un nombre ldgico (especificado por el administrador de servidor de ap1icaci6n) en el servicio J N D I indicado en el Paso 1.

O La aplicaci6n JDBC (cliente) realiza una busqueda en el servicio J N D I utilizando este nombre bgico, y recupera el objeto implementando la interfaz j a v a x . sql .D a t a S o u r c e . Este es el segundo paso del diagrama.

Programacion de bases de datos con JDBC


O

La aplicacion JDBC (cliente) utiliza el objeto DataSource y obtiene conexiones de base de datos, corno indica el Paso 3 . La irnplernentaci6n de la fuente de datos puede que utilice el driver JDBC para recuperar una conexion. La aplicacion JDBC (cliente) utiliza el objeto Connection para el acceso a todas sus bases de datos, utilizando el API JDBC estindar, el paso final en la secuencia.

Analicernos 10s detalles de 10s tres prirneros pasos.

Crear una fuente de datos


~ s t es e un proceso sencillo y conlleva instanciar un objeto que irnplernente el objeto j a v a x . s q l .D a t a S o u r c e y asociarlo a un nornbre. Esto esti ilustrado a continuaci6n.
X D a t a S o u r c e x = new X D a t a S o u r c e ( . . . ) ; / / Configurar propiedades para l a fuente de datos

//
try

Crear

un

contexto

C c ' r i t e x t c o n t e x t = new I n i t i a l C o n t e x t ( ) ; c o n t e x t . b i n d ( " j d b c / O r d e r s " , x );

1 c a t c h (NamingExceptlon n e ) ( / / Error a1 c r e a r e l contexto


I

asociaci6n.

En el fragment0 de codigo anterior, X d a t a s o u r c e es una clase que irnplernenta la interfaz j a v a x . s q l .D a a S o u r c e , irnplernentada por 10s vendedores de driver y base de datos. Observe que el verdadero nornbre de esta clase es irrelevante para el desarrollador de la aplicaci6n. En su lugar, utilizarnos el nornbre 16gico asignado a D a t a S o u r c e . En el ejernplo anterior, este es j d b c / O r d e r s . A1 cornpararlo con el enfoque basado en j a v a . s q l D r i v e r M a n a g e r , el anterior sustituye la inicializacion estitica realizada por 10s drivers a1 registrar un driver.

L a c l a s e ~ n i t i a l c o n t e x es t unaclase queirnplernenta lainterfaz j a v a x .Naming. C o n t e x t del API JDBC. Dependiendo del entorno (lado cliente o lado servidor) en el que creamos el contexto inicial, puede que tengarnos que utihzar el constructor I n i t i a l c o n t e x t que torna un objeto ~ a s ha t b l e corno argurnento. Este H a s h t a b l e debe contener ciertos atributos de entorno que dirijan la creaci6n del contexto inicial. Algunos de 10s atributos rnis cornhrnente utilizados incluyen j a v a . n a m i n g . p r o v i d e r . u r l , j a v a . n a m i n g . s e c u r i t y . p r i n c i p a l y j a v a . n a m i n g . security.credentials.Estosatributos especifican un proveedor (un URL que apunta a un servicio JNDI) del servicio JNDI, la identidad (principal) de la aplicaci6n o del usuario en cuyo nornbre es creado este contexto, y las credenciales del principal. Mientras que el primer atributo especifica una posicion del servicio JNDI, el segundo y tercer atributo especifican la identidad del Ilarnante. Estos dtirnos argurnentos pueden ser utilizados para irnplernentar seguridad y control de acceso para el JNDI. Si desea una lista cornpleta de estos atributos, consulte la docurnentacion de la interfaz j a v a x . n a m i n g . c o n t e x t (disponible enhttp://java.sun.coWproducts/jndi/javadoc/java~naming~ ContexLhtml). Observe que tanto el constructor de la clase j a v a x . n a m i n g . I n i t i a l c o n t e x t corno el rnetodo de asociacion lanzan j a v a x . n a m i n g . N a m i n g E x c e p t i o n . Esta exception es la clase raiz de todas ]as excepciones relacionadas con JNDI. TarnbiCn es conveniente mencionar que el paso anterior es supervisado por el proveedor de senidor de aplicacidn J2EE. Es decir, cuando iniciarnos el servidor de aplicaci6n JZEE, Cste instancia clases que

Capitulo 4
irnplernentan la interfaz javax.sql.DataSource y asocia estos objetos a nombres 16gicos del senicio JNDI. Fijese en que la rnayoria de 10s senidores de aplicacih J2EE tarnbikn incluyen un senicio JNDI, por lo que puede no ser necesario configura uno fuera del senidor de aplicaci6n. Aunque algunos de 10s vendedores de aplicacion J2EE implernentan la interfaz j avax . s q l .D a t a S o u r c e sobre drivers JDBC existentes, existen irnplernentaciones j avax. s q l .DataSource procedentes de diferentes vendedores debases de datos. En el rnornento de configurar el senidor de aplicacidn J2EE, seri preciso que aiiadarnos la configuracion de la fuente de datos para 10s drivers de base de datos que pensarnos utilizar. Hay dos situaciones diferentes:
O El senidor de aplicaci6n que irnplernenta el paquete j avax s q l con driver JDBC de terceros. En

este caso, seri necesario que especifiquernos la clase javax. s q l .Driver a1 configurar el senidor de aplicacion. especificar la clase que irnplernenta la interfaz j avax .s q l .Datasource. Podemos obtener esta inforrnaci6n del vendedor del driver y en la docurnentacibn.

O El vendedor de driver JDBC que irnplementa el paquete javax sql: en este caso, seria necesario

En arnbos casos, cabe seiialar que existe una capa adicional entre 10s drivers de base de datos tradicionales y el API que utilizarnos para obtener conexiones.

Recuperar un objeto DataSource


Una vez que el senidor de la aplicaci6n ha asociado un objeto DataSource en el senicioJND1, cualquier aplicaci6n cliente JDBC de la red puede recuperar el objeto DataSource utilizando el nombre 16gico asociado a la fuente de datos. El siguiente fragment0 de c6digo ilustra este caso:
//
Crear un contexto

C o n t e x t c o n t e x t = new DataSource d a t a s o u r c e

InitialContext ( ) ; (DataSource) c o n t e x t . lookup ( " j d b c / x " );

I
c a t c h ( NarningExceptlon ne) el conexto o l a b6squeda.

1
//
Error a1 crear

El proceso es rnuy sencillo: crearnos un objeto Initialcontext y realizamos una bfisqueda utilizando el nornbre 16gico asignado durante la configuracih del senidor. Puesto que un senicio J N D I existe habitualrnente en una VM diferente y, norrnalmente, en una rniquina diferente, la operaci6n lookup ( ) seri, por lo general, una operacidn rernota. De este hecho, podernos deducir que las clases de implernentaci6n DataS ource tambien implementan la interfaz
java.io.Serializable.

Caracteristicas clave
Fijese en las siguientes caracteristicas clave de utilizar un rnetodo de fuente de datos:
O N o es necesario que cada aplicaci6n cliente inicialice 10s drivers JDBC. Corno hernos visto

anteriorrnente, 10s drivers JDBC requieren inicializaci6n en cada aplicacibn cliente. Esto n o seri necesario con el paquete j avax. sql. En carnbio, es preciso que el senidor de aplicacidn convierta en disponibles 10s objetos de fuente de datos en el servicio JNDI.

Programacion de bases de datos con JDBC


0

La aolicaci6n cliente no tiene Dor quC conocer 10s detalles del driver. La Gnica informaci6n requerida es un nombre 16gico. Esto hace que el cddigo de aplicaci6n sea independiente de 10s drivers y de 10s URLs JDBC.
L
A

Puesto que este enfoque utiliza un servicio J N D I para localizar 10s objetos de fuente de datos utilizando nombres kgicos, este enfoque proporciona una bhqueda independiente de la posicion de las fuentes de datos. Los objetos Datasource pueden ser creados, desplegados y gestionados en un servicio J N D I , independiente de todas 10s clientes de aplicaci6n.

Revision del catalog0 de peliculas


Modifiquemos ahora la apkaci6n del catilogo de peliculas para utilizar una fuente de datos. S61o hay dos cambios que realizar a 10s archivos CreateMovieTable . java y QueryMovieTable .j ava.Estos son analizados a continuacibn:
import import import import import import import j ava. sql . DriverManager; j ava. sql. Connection; java.sql.Statement; java.sql.ResultSet; j a v a . sql. DatabaseMetaData; java.sql.Resu1tSetMetaData; java.sq1.SQLException;

/ / Importar clases javax.sq1 import javax. sql. DataSource; / / Importar clases JNDI import javax. naming.Context; import j avax. naming .NamingException;

Fijese en las dos instrucciones de importaci6n adicionales para irnportar clases desde 10s paquetes javax.sqlyjavax.naming. El otro cambio se encuentra en el mktodo initialize ( ) en el que cargamos orginalmente el driver y creamos una conexi6n. En lugar se esto, debemos ahora obtener un objeto j avax .sql .DataSource y crear una conexibn:
public void i n i t i a l i z e 0 throws SQLException, NaminqException { / / En vez d e registrar el driver como a continuaci6n /* Class. forName (driver); / / buscar y obtener un objeto DataSource d e JNDI Context initialcontext = n e w InitialContext [ ) ; datasource = [DataSource) initialContext.lookup("jdbc/Cloudscape");

/ / Reemplazar // connection = D r i v e r M a n a g e r . g e t C o r ~ r ~ e c t i o ( r tu r l ) ; / / utilizando el objeto DataSource para obtener una conexi6n. connection = datasource .getConnection ( ) ;
\

Laprimera instrucci6n creaun objeto j avax .naming.Context.La clase Initialcontext implements la interfaz j avax .naming.Context y proporciona el punto de partida para la resoluci6n de nombres en el servicio JNDI. e En el ejemplo anterior, utilizamos init ialcont ext para buscar en j dbc/Cloudscape. ~ s t es nombre que especificamos a1 configurar el servidor aplicaci6n, de mod0 que el servidor aplicaci6n pueda crear una instancia de j avax. sql .DataSource y asociarla con el nombre j dbc/

Capitulo 4
C l o u d s c a p e en el servicio J N D I . j d b c es el subcontexto de nombrado estindar para todos 10s objetos~atasource. El mktodo l o o k u p ( ) devuelve un objeto que implementa la interfaz j a v a x . s q l D a t a s o u r c e . Puesto que el mktodo l o o k u p ( ) devuelve un objeto j a v a . l a n g ~b j e c t , necesitamos enviarlo a javax.sql.DataSource.

El resto de las operaciones de la base de datos se realizan de forma habitual. Para poner en prictica esta aplicaci6n, necesitamos un servidor de aplicaci6n J2EE que se ajuste a las fuentes de datos para aplicaciones cliente.

Reserva de conexiones
Una aplicaci6n de servidor, por definici6n, realiza un servicio para uno o rnis clientes. A medida que aumenta el numero de clientes, tambikn aumenta la importancia de servir a1 cliente del mod0 rnis eficiente posible. Una de las tkcnicas utilizadas para servir de forma eficiente las solicitudes de 10s clientes es la reutilizacibn exhaustiva de objetos de recursos costosos. Siempre hay un sobregasto en la creaci6n de un objeto (gasto de memoria, inicializaci6n del objeto y la JVM debe mantener un registro del objeto de forma que pueda ser recogido por el recolector de residuos cuando ya no sea necesario). En general, es una buena idea minimizar el numero de objetos que creamos en las aplicaciones; tanto rnis en las aplicaciones de lado servidor (como aplicaciones Web), donde 10s ndmeros de clientes y solicitudes de clientes no son ficilmente predecibles. Ademis, 10s objetos que encapsulan las conexiones de red son mis caros de crear que otros. Si podemos reutilizar un objeto, el rendimiento del servidor puede mejorar extraordinariamente. La reserva de conexiones es una tkcnica destinada a gestionar y reutilizar objetos. Puesto que crear objetos C o n n e c t i o n es una de las operaciones mas caras en tkrminos de recursos, el tip0 rnis frecuente de reserva de objeto suele ser la reserva de conexiones. En JDBC, un objeto c o n n e c t i o n representa una conexi6n nativa de base de datos (except0 en bases de datos integradas en la memoria, que no son muy comunes en sistemas de producci6n). El servidor de base de datos debe distribuir recursos de comunicaci6n y de memoria asi como autentificar el usuario y configurar un context0 de seguridad para cada conexi6n. Aunque existen varios parimetros que dictan el tiempo para obtener una conexi61-1, no es usual ver tiempos de conexion de uno o dos segundos (dependiendo de la conexi6n, carga de base de datos, etc.).kompartiendo un conjunto de conexiones entre clientes, en lugar de intentar crearlas cada vez que sean necesarias, podemos mejorar las cargas en 10s recursos y, consecuentemente, la capacidad de respuesta de la aplicaci6n. Una reserva de conexiones de base de datos beneficia a la mayoria de aplicaciones de lado servidor que accede a una base de datos. Utilice una reserva de conexiones si las siguientes caracteristicas describen su aplicaci6n:
0 Los usuarios acceden a la base de datos a travks de un pequefio conjunto comun de cuentas de usuario de base de datos. La alternativa es que cada usuario utiliza una cuenta especifica. En aplicaciones centradas en Internet, las cuentas comunes de usuarios son rnis frecuentes.

q r Una conexi6n de base de datos s61o se utiliza durante una unica solicitud, en oposici6n a la
'

duraci6n combinada de multiples solicitudes de la misma sesi6n.

El segundo criterio es rnis interesante. Una tipica aplicaci6n de e-comercio permite a 10s usuarios afiadir elementos a un carro de la compra a su antojo mientras navegan por la pigina. Cuando 10s usuarios terminan sus compras, pasan por caja y pagan 10s contenidos del carro. Podemos disehar esta aplicaci6n a1 menos de dos formas:

Programacion de bases de datos con JDBC


O El carro de la compra es una tabla de base de datos. Cuando el usuario entra en la pigina, obtenemos una conexion de base datos y la mantenemos hasta que el usuario pasa por caja o sale de la pigina (o despuks del tiempo limite de la sesidn). Cada articulo afiadido a1 carro significa afiadir una fila a la tabla. Si el usuario pasa por caja, realizamos la transaccion de base de datos y si el usuario sale de la pigina sin comprar, deshacemos la transaccibn. Si la aplicacibn sigue este disefio, no es necesaria una reserva de conexibn ya que cada conexion esti asociada a las actualizaciones de datos en el carro y no puede ser compartida. O El contenido del carro de la compra se mantiene en un objeto normal integrado en la memoria asociado a1 usuario. Por ejemplo, en una aplicacibn Web basada en un servlet/JSP, este objeto puede ser mantenido en el objeto H t t p S e s s i o n . Cada articulo ahadido a1 carro significa ahadir el articulo a1 objeto integrado en la memoria. Si el usuario pasa por caja, obtenemos una conexion a la base de datos, afiadimos todos 10s articulos del objeto integrado en la memoria como filas en una tabla de base de datos, y realizamos la transaccibn. Si el usuario sale de la pigina sin comprar, simplemente suprimimos el objeto integrado en la memoria. Este modelo satisface 10s criterios anteriores por lo que podemos utilizar una reserva de conexiones.
El paquete j a v a x . s q l proporciona una reserva de conexiones basada en una fuente de datos que es transparente a las aplicaciones de cliente. C o m o veremos en breve, en este enfoque, la reserva de conexiones puede ser activada y configurada por un administrador de un servidor de aplicacibn J2EE que se ajuste a esta caracteristica. El enfoque tradicional ha ido unitindose programiticamente durante tiempo a1 enfoque de reserva de conexiones. Observe que hay algunas variantes de este enfoque tradicional disponibles, como DBConnect i o n p o o l analizada en la primera edicibn de este libro (tambiCn disponible en un breve articulo enhttp://www.Webdevelopersjournal.com/colurnnconnectionpool.htrnl) y D B C o n n e c t i o n B r o k e r (disponible en http://javaexchange.corn). Aunque estas reservas ofrecen una amplia gama de servicios, en principio son muy similares. Antes de analizar 10s conceptos subyacentes a1 apoyo JDBC para la reserva de conexiones, veamos como se realiza una reserva de conexiones tradicional.

Reserva de conexiones tradicional


En este enfoque, una aplicacion:

CI Obtiene una referencia a la reserva o a un objeto que gestiona varias reservas O Consigue una conexi6n de una reserva O Utiliza la conexibn
O

Devuelve la conexion a la reserva

La aplicacidn es completamente consciente de que esti utilizando una conexion de reserva, por lo que nunca debe cerrar la conexion. En su lugar, debe devolver la conexibn a la reserva. La implementation del modelo clisico consiste normalmente en una clase (por ejemplo, c o n n e c t i o n p o o l ) que gestiona un conjunto de objetos c o n n e c t i o n JDBC. Esta clase proporciona mktodos para inicializar la reserva (para fijar el nGmero de conexiones que deben ser abiertas en el arranque, URL de JDBC, el n6mero miximo de conexiones, etc), para obtener conexiones y para devolver conexiones. Los clientes de esta clase inicializan primer0 la reserva antes de obtener conexiones. El siguiente diagrama ilustra esta situacidn:

Capitulo 4

Crear una reserva

Obtener una conexion

Devolver la conexion

!
1
Aplicacion JDBC
)

Driver JDBC

L-*~uente

de datos

Corno vernos en la figura anterior, la reserva de conexiones es tratada corno una responsabilidad del cliente. La aplicacion cliente crea la reserva, recupera las conexiones y libera las conexiones de nuevo. Adernis de esto, este enfoque requiere un contrato estricto por parte del desarrollador cliente de aplicacion:
0 La aplicaci6n cliente no debe cerrar la conexion; solo debe devolverla a la reserva. U n contrato corno Cste, sin embargo, no puede ser aplicado estrictarnente en aplicaciones cliente. Si el cliente cierra accidentalrnente la conexion antes de devolverla a la reserva, la conexion seri inservible; la reserva elirninari la referncia a ella y la recreari si es necesario.
0

Cuando el cliente utiliza el objeto Connection en una transaccion y olvida terrninar (aceptar o deshacer) la transaccion, la reserva de conexiones no puede detectarlo. Esto provoca que las transacciones se rnezclen y que se produzca una pCrdida de consistencia de datos.

Aunque estos puntos pueden cuidarse codificando las pricticas concienzudarnente, la irnplernentaci6n de reservas de conexiones consistentes es todavia responsabilidad de la aplicacion cliente. Esta clisica,reserva de conexiones es vilida unicarnente para clientes que cornparten el rnisrno periodo de ejecucion. Esta es una reserva de lado cliente. Dentro del alcance de este libro, hay dos posibilidades en las que multiples clientes cornparten el rnisrno entorno:
0 Las aplicaciones Web JZEE desplegadas en un unico contenedor. En este caso, multiples servlets y objetos JSP serin invocados en diferentes threads per0 en el rnisrno periodo de ejecucion (siernpre que el contenedor no sea distribuido). 0 Una aplicacion de servidor multi-thread que proporcione rnCtodos de ernpresa para el acceso a bases de datos por parte de 10s clientes.

Cuando se requieren conexiones desde diferentes aplicaciones cliente, la clisica reserva no es la election adecuada. Para esos casos, seria rnis conveniente una reserva de conexion de lado servidor. Cuando cada cliente rnantiene su propia reserva de conexion, es probable que la reutilizaci6n de conexiones no sea optima. Una reserva de conexiones de lado servidor evita esta situation. Como verernos en la siguiente seccion, el API JDBC especifica reservas de conexiones que curnplen este requisito. Actualrnente, la rnayoria de 10s servidores de aplicacion JZEE ofrecen esta funci6n.

Programacion de bases de datos con JDBC


Dejando a un lado 10s detalles sobre qut clases son utilizadas para albergar conexiones, este enfoque n o es solido ni reajustable. El defect0 fundamental de la reserva clisica de conexiones es que esta reserva no funciona con transacciones distribuidas. Tambitn hace estragos en 10s entornos controlados por contenedores como contenedores Web, ya que le obliga a mantener conexiones en variables estiticas, sobre las que el contenedor no puede ejercer su control.

Reserva de conexiones con el paquete javax.sql


El paquete javax.sql proporciona un rnedio transparente de reserva de conexi6n. Con este enfoque, el servidor de aplicacion y/o el driver de base de datos maneja la reserva de conexiones de forma interna. Siempre que usemos 10s objetos DataSource para obtener conexiones, la reserva de conexiones se activari automiticamente una vez configuremos el servidor de aplicaci6n J2EE. Antes de entrar en 10s detalles de este enfoque, aqui tiene una visi6n esquemitica:

1.Asoc~ar objeto DataSource


2.

B6squeda del

7
3

SeN1cloJND1 + I

/
t

lnfraestructura de se~ld0r de
apl1cac16n

Obtener conexlon de DataSource conexlones

Conex~on de reserva
4

Dr~ver JDBC
I

Base de datos

Utlllzar el objeto connection para el acceso a datos

La cOnexlon utlllzauna conexlon de reserva para acceso a 10sdatos

el

En comparaci6n con la primera figura, el h i c o cambio es la reserva de conexiones adicional mantenida por el servidor de aplicaci6n en coordinaci6n con el driver JDBC. Esto significa que no es preciso programaci6n adicional para las aplicaciones de cliente JDBC. En su lugar, el administrador del servidor J2EE tendri que configurar una reserva de conexiones en el servidor de aplicacion. La sintaxis exacta y 10s nombres de las clases dependen de la implementaci6n. Sin embargo, con un servidor de aplicaci6n y un driver de base de datos que se ajusten a JDBC 2.0 el administrador de servidor especifica normalmente lo siguiente:
O

Unaclasequeimplementalainterfaz j avax .sql .ConnectionPoolDataSource

Una clase que implementa lainterfaz java .sql .Driver

O El tamafio de la reserva (tamafio miximo y minirno)

Capitulo 4
0 Tiempo limite de la conexi6n 0 Parimetros de autentificaci6n (registro, contraseiia, etc.)

En el resto de esta seccibn, analizaremos las interfaces relacionadas con la reserva de conexiones y c6mo se implements la reserva de conexiones utilizando estas interfaces. El proposito de esta secci6n es ofrecerle una visi6n de la reserva de conexiones de JDBC 2.0. Ademis de configurar el servidor J2EE para activar la reserva de conexiones, las aplicaciones de cliente no necesitan implementar o acceder a estas interfaces directamente. El paquete j avax. sql especifica tres interfaces y una clase para la implementaci6n de reservas de conexiones: javax. sql. ConnectionPoolDataSource, javax. sql. PooledConnection,
javax.sql.ConnectionEventListeneryjavax.sq1.ConnectionEvent.

La interfaz javax.sql.ConnectionPoolDataSource
Esta interfaz es simi1ar.a la interfaz javax. sql. DataSource. En vez de devolver objetos j ava. sql. Connection,estainterfazdevuelveobjetosj avax. sql. P o o l e d C o n n e c t i o n . E s d e c i r , ~ a fuente de datos de reserva de conexiones es una factoria para objetos de conexion de reserva. Los siguientes metodos devuelven objetos j avax. sql . PooledConnection:
public

javax.sql.PooledConnection getPooledConnection() throws java.sql.SQLException


javax.sql.PooledConnection getpooledconnection throws java.sql.SQLException
(String user, String password)

public

Los metodos restantes de esta interfaz son 10s mismos que 10s de la interfaz j avax. sql .DataSource. Incluso despuks de que hayamos configurado la reserva de conexiones, las aplicaciones todavia utilizan objetos javax . sql .DataSource para obtener objetos de conexi611, como hemos visto en el mktodo initialize ( ) delaaplicaci6ndelcatilogo depeliculas. Es elobjeto j avax. sql. Datasource el que utiliza j avax .sql .Connect ionPoolDat asource para crear y mantener una reserva de conexiones. ~ s t es a una parte de la implementaci6n de DataSource (proporcionada por el vendedor de driver o de servidor)?La reserva de conexiones se mantiene transparente a1 c6digo de aplicacion. Una vez que el administrador establece la reserva de conexiones, empezaremos automaticamente a utilizar las conexiones de reserva.

La interfaz javax.sql.PooledConnection
Cuando se activa una reserva de conexiones, 10s objetos que implementan la interfaz j avax. sql .PooledConnection albergan unaconexidn de base de datos fisica. Esta interfaz es una factoria de objetos j avax . sql .Connection. Esta interfaz especifica 10s siguientes mktodos:
public java.sql.Connection getconnection() throws java.sql.SQLException

Este metodo devuelve un objeto j ava . sql .Connection.Sin embargo, el objeto Connection devuelto es realmente un asa (o proxy) para la conexi6n fisica que mantiene el objeto javax.sql.PooledConnection.
public void close() throws java.sql.SQLException

Este mktodo cierra la conexi6n a la base de datos.

Pro~ramacion de bases de datos con JDBC


Pero, icual es la diferencia entre una conexi6n de reserva y una conexi6n?

O En primer lugar, la conexi6n es una conexi6n fisica en aplicaciones cliente JDBC. Con la reserva de
conexiones JDBC, el objeto c o n n e c t i o n no alberga una conexi6n de base de datos fisica. Lo que la aplicaci6n obtiene es una abstracci6n de un objeto c o n n e c t i o n corriente. El objeto c o n n e c t i o n utiliza la conexion fisica que alberga el objeto c o n n e c t i o n de reserva para el acceso a todos sus datos.
0

En segundo lugar, cuando invocamos el metodo c l o s e ( ) , la conexi6n fisica n o se cierra. La implementaci6n D a t a s o u r c e elimina meramente la asociacion entre el objeto de conexi6n y el objeto c o n n e c t i o n de reserva. Podemos, por lo tanto, cerrar la conexi611 despuis de utilizarla; es entonces cuando la fuente de datos reutiliza la conexi6n de reserva. Simplemente lo cerramos, como hariamos sin reserva de conexiones.

0 En tercer lugar, n o es necesario que devolvamos el objeto c o n n e c t i o n a ninguna reserva.

En otras palabras, el objeto c o n n e c t i o n es un envoltorio sobre P o o l e d C o n n e c t i o n . Cuando la fuente de datos devuelve una conexion, mantiene una asociaci6n entre el objeto c o n n e c t i o n devuelto y el objeto P o o l e d C o n n e c t i o n , de mod0 que las llamadas sobre el o b j e t o c o n n e c t i o n son delegadas en elobjeto~ooled~onnection. La interfaz j a v a x . s q l . P o o l e d C o n n e c t i o n tiene dos mitodos mis para manejar la asociaci6n entre la conexi6n y la conexi6n de reserva. Recuerde que cuando se cierra el objeto c o n n e c t i o n , la reserva de conexiones debe ser notificada, de mod0 que la conexidn de reserva pueda ser reutilizada:
public void addConnectionEventListener(ConnectionEventListener listener) public void removeConnectionEventListener(C0nnectionEventListener listener)

Estos dos metodos son utilizados por la reserva de conexiones para afiadir y eliminar escuchantes de eventos de conexi6n.

La interfaz javax.sql.ConnectionEventListener
La i n t e r f a z ~ o n n e c t i o n ~ v e n t ~ i s t etiene n e r dos mitodos:
public void connectionClosed(ConnectionEvent event)

Este metodo es invocado cuando la aplicaci6n llama a1 metodo c l o s e ( ) . La reserva de conexiones marca la conexion para su reutilizaci6n.
public void connectionErrorOccured(ConnectionEvent event)

Este metodo es invocado cuando ocurren errores fatales de conexi6n. La reserva de conexi6n puede cerrar la conexi6n en este evento y eliminarlo de la reserva.

La clase javax.sql.ConnectionEvent
Esta clase representa 10s eventos relacionados con conexiones. Observe que este mecanismo de manejo de eventos es similar a 10s eventos AWT. La reserva de conexiones afiade escuchantes de eventos de conexi6n a la conexion de reserva y 10s escuchantes de conexi6n son notificados cuando tienen lugar 10s eventos de conexi6n.

Irnplementacion de reservas de conexion


El API JDBC no especifica ningiin algoritmo concreto para reserva de conexiones. Las interfaces que hemos analizado anteriormente son ganchos para implementar una reserva de conexiones. En una

Capitulo 4
irnplernentacion tipica, se suceden 10s siguientes pasos cuando invocarnos g e t c o n n e c t i o n ( ) en la fuente de datos:
0

La fuente de datos prirnero cornprueba un objeto P o o l e d C o n n e c t i o n libre. Si hay uno, la reserva de conexiones devuelve un objeto P o o l e d C o n n e c t i o n a la fuente de datos. La fuente datos invoca entonces g e t c o n n e c t i o n ( ) en el objeto P o o l e d c o n n e c t i o n , que devuelve un objetoconnection. de datos utiliza una fuente de datos de reserva de conexiones para obtener una nueva conexi6n de reserva.

0 Si n o hay un objeto P o o l e d C O n n e c t i o n libre disponible en la reserva de conexiones, la fuente

- Cornopodernos ver, lainterfaz j a v a x . s q l .ConnectionPoolDataSourcees una factoriapara objetos


j a v a x . s q l . PooledConnection.adernis,lainterfazj avax. s q l . ~ooled~onnectionesunafactoria para objetos java.sql.Connection. j a v a x s q l .D a t a s o u r c e irnplernenta la reserva de conexiones y coordina las conexiones de reserva y las conexiones regulares con la ayuda de las interfaces exarninadas.

Corno una conexi6n es rnerarnente un a s para una conexi6n de reserva (que alberga la conexi6n de red), una conexibn puede ser creada y cerrada varias veces utilizando la rnisrna conexi6n de reserva. Adernis, el API cliente (las interfaces j a v a x . s q l . D a t a s o u r c e y j a v a . s q l . c o n n e c t i o n ) sernantiene igual porque 10s detalles de la reserva de conexiones nunca son expuestos a la aplicaci6n. Una vez rnis, la principal ventaja de este enfoque es su sencillez, tanto para 10s desarrolladores de aplicaciones corno para 10s adrninistradores de sisternas. Los adrninistradores de sisternas pueden activar/ configurar la reserva de conexiones independienternente de todas las aplicaciones.

A1 exarninar la interfaz j a v a .s q l C o n n e c t i o n , analizarnos brevernente las transacciones. La interfaz j a v a . s q l . C o n n e c t i o n tiene dos rnktodos, c o m m i t ( ) y r o l l b a c k 0 , para realizar y deshacer carnbios, respectivarnente. Controlarnos 10s lirnites (el inicio y el final) de la transacci6n invocando s e t A u t ocommi t ( f a l s e ) a1 principio de la transacci6n e invocando el rnktodo r o l l b a c k ( ) o el metodo c o m m i t ( ) para finalizar la transacci6n. .Tales transacciones son denorninadas transacciones locales. En una transaccibn local, las aplicaciones cliente ejecutan operaciones de lectura y escritura/actualizaci6n debase de datos sobre un objeto c o n n e c t i o n . En deterrninadas situaciones, sin embargo, tenernos rnis de un cliente (por ejernplo, dos servlets diferentes o cornponentes EJB) participando en una transacci6n. Alternativarnente, el cliente puede que tenga que ejecutar dos operaciones de base de datos en multiples bases de datos en la rnisrna transacci6n. tC6rno podernos irnplernentar estas caracteristicas? Aqui es cuando intervienen las transacciones distribuidas. El paquete j a v a x . s q l , junto con Java Transaction API UTA) puede utilizarse para irnplernentar transacciones distribuidas. En esta secci6n, realizarernos un anilisis de las transacciones distribuidas y verernos las interfaces relevantes de JDBC y JTA.

iQue es una transaccibn?


Las aplicaciones de ernpresa a rnenudo requieren acceso concurrente a datos distribuidos cornpartidos por multiples cornponentes, para ejecutar operaciones en datos. Tales aplicaciones deben rnantener la

Programacion de bases de datos con JDBC


integridad de datos (tal y corno estin definidos por las reglas de empresa de la aplicaci6n) en las siguientes circunstancias:
0

Acceso distribuido a u n unico recurso de datos Por ejemplo, podemos tener dos componentes de aplicacidn que implementan dos partes de una transacci6n de empresa; ambos utilizan la misma base de datos per0 diferentes conexiones. Acceso a recursos distribuidos desde u n dnico componente de aplicaci6n Por ejemplo, un componente que actualiza multiples bases de datos en una unica transacci6n de empresa. Esta operaci6n requeriria multiples objetos connect ion.

En ambos casos, 10s mktodos proporcionados por el API JDBC central no son adecuados. Esto se debe a que 10s mktodos proporcionados en j ava .s q l .connect ion para iniciar y finalizar transacciones estin asociados a un h i c o objeto connection. En las situaciones anteriores, sin embargo, n o ocurre esto. El concept0 de transaccidn y de gestor de transacciones (o servicio de procesamiento de transacciones) simplifica el desarrollo de tales aplicaciones a1 mantenimiento de la integridad de datos en una unidad de trabajo como se describe en las propiedades ACID, garantizando que una transacci6n nunca queda incompleta, que 10s datos nunca son inconsistentes, que las transacciones concurrentes con independientes, que 10s efectos de una transacci6n son persistentes. En la siguiente secci6n aprenderi que representan las sigl& A C I D y c6mo las propiedades A C I D son mantenidas por 10s sistemas de procesamiento de transacciones.

Antecedentes
En el dominio del ~rocesamiento de transacciones distribuidas, el modelo X/ODen Distributed Transaction Processing (DTP) es el modelo mas adoptado para la construcci6n de aplicaciones transaccionales. Casi todos 10s vendedores que desarrollan programas relacionados con el procesamiento de transacciones, bases de datos relacionales y colas de mensajes, se ajustan alas interfaces definidas en el modelo DTP. Este modelo define tres componentes:
0 Programas de aplicacion

0 Gestores de recursos
0

Gestor de transacciones

Este modelo tambikn especifica interfaces funcionales entre programas de aplicaci6n y el gestor de transacciones (conocido como interfaz TX), y entre el gestor de transacciones y 10s gestores de recursos (la interfaz XA). Utilizando 10s gestores de transacciones que se ajusten a T X y 10s gestores de recursos que se ajusten a XA (como las bases de datos), podemos implementar transacciones con el protocolo bifisico de realizar y recuperar para cumplir 10s requisitos para las transacciones. El servicio de transacci6n de objetos, Object Transaction Service (OTS), es otro modelo de procesamiento de transacciones distribuidas especificado por el grupo de gesti6n de objetos, Object Management Group (OMG). Este modelo esti basado en el modelo X/Open DTP y sustituye las interfaces funcionales T X y XA por interfaces CORBA I D L (Common Object Request Broker Architecture Interface Definition Language). En este modelo, 10s diversos objetos se comunican mediante llamadas de metodo CORBA sobre Internet Inter ORB Protocol (IIOP). I I O P ha sido especificado por O M G especificamente para implementar soluciones CORBA en Internet. El modelo OTS es interoperable con el modelo X/Open DTP. Una aplicaci6n que utilice objetos transaccionales podria utilizar la interfaz XT con el gestor de transacciones para la demarcaci6n de transacciones.

Capitulo 4
En la arquitectura J2EE, el JDBC y el Java Transaction API proporciona interfaces para implementar transacciones distribuidas. Ademis, el servicio de transacciones Java, Java Transaction Service (JTS) especifica una representaci6n de OTS.

Procesamiento de transacciones

- Conceptos

Antes de proceder a examinar 10s API relevantes de JDBC y JTA, analicemos brevemente algunos de 10s conceptos asociados a las transacciones distribuidas:
O O

Demarcaci6n de transacciones Contexto de transacciones y propagaci6n

0 Alistamiento de recursos 0

Realizaci6n en dos fases

Comenzaremos con la demarcaci6n de transacciones.

Dernarcacion de transacciones
Una transaction puede ser especificada por lo que se conoce como demarcaci6n de transacciones. La demarcaci6n de transacci6n permite que el trabajo realizado por componentes distribuidos se asocie a una transacci6n global. Por ejemplo, para transacciones locales en el momento que creamos una transacci6n e invocamos s e tAutoCommi t ( f a l s e ) , iniciamos una transacci6n. D e un mod0 similar, una llamada a commit ( ) o r o l l b a c k ( ) finalizalatransacci6n. Esto no es asi para transacciones distribuidas. El enfoque mis comun a la demarcaci6n es tomar el thread que ejecuta las operaciones y marcarlo para el procesamiento de transacci6n. Esto es lo que se denomina demarcacion programitica. La transacci6n establecida de este mod0 puede ser suspendida desmarcando el thready retomada mis tarde marcando de nuevo el thread. Para marcar y retomar la transacci61-1, el context0 de transacci6n debe ser propagado explicitamente hasta el thread en el que retoma la transacci6n. Sin embargo, con sistemas de procesamiento de transacciones como 10s contenedores EJB, esto se convierte en responsabilidad del contenedor.

La demarcaci6n de transacci6n finaliza despuks de una solicitud de realizar o deshacer a1 gestor de transacciones. La solicitud realizar (commit) dirige todos 10s gestores de recursos participantes a ejecutar 10s efectos de las operaciones de la transacci6n permanente. La solicitud de deshacer (rollback) da instrucciones a 10s gestores de recursos para que deshagan 10s efectos de todas las operaciones realizadas sobre la transacci6n.
Una alternativa a la demarcaci6n programitica es la demarcacion declarativa. En esta tkcnica, 10s componentes son marcados como transaccionales en el momento de despliegue. Esto tiene dos implicaciones:
O

Primero, la responsabilidad de demarcaci6n cambia pasa de la aplicaci6n a1 contenedor que alberga el componente. Por este motivo, esta tkcnica tambikn es denominada demarcaci6n controlada por contenedor. tiempo de despliegue del componente (dinimico).

0 Segundo, la demarcaci6n es pospuesta desde el tiempo de construcci6n de aplicaci6n (estitico) a1

Los sistemas de procesamiento de transacciones basados en componentes tales como servidores de aplicaci6n basado en la especificaci6n Enterprise JavaBeans y Microsoft Transaction Server cumplen la demarcacion declarativa.

Procramacion de bases de datos con JDBC

Contexto de transacciones y propagacion


Puesto que en una transaction participan multiples componentes de apkaci6n y recursos, es necesario que el gestor de transacciones establezca y mantenga el estado de la transacci6n segun ocurre. Esto se realiza normalmente en forma de contexto de transaccih. El contexto de transacci6n es una asociaci6n entre las operaciones transaccionales en 10s recursos y 10s componentes que invocan las operaciones. Durante el transcurso de una transacci611, todos 10s hilos que participan en la transacci6n comparten el contexto de transaccion. Asi el contexto de transaccion envuelve 16gicamente todas las operaciones ejecutadas sobre recursos transaccionales durante una transaccion. El gestor de transacciones subyacente mantiene normalmente el contexto de transaccidn de forma transparente. Por ejemplo, un cliente Java o un componente EJB que implemente transacciones no necesita explicitamente propagar el contexto. El contenedor subyacente J2EE lo maneja.

Alistamiento de recursos
El alistamiento de recursos es el proceso mediante el cual 10s gestores de recursos informan a1 gestor de transacciones para que participen en una transaccion. Este proceso permite al gestor de transacciones registrar todos 10s recursos que participan en una transaccion. El gestor de transacciones utiliza esta informaci6n para coordinar el trabajo transactional ejecutado por 10s gestores de recursos y para dirigir el protocolo bifasico de realizacidn y recuperacidn. A1 final de una transaccion (despues de aceptar o deshacer), el gestor de transacciones libera 10s recursos. DespuCs, la asociaci6n entre las transacciones y 10s recursos n o se mantiene.

Aceptar en dos fases


Este protocolo entre el gestor de transacciones y todos 10s recursos alistados para una transaccion certifica que todos 10s gestores de recursos acepten ( c o m m i t ) la transacci6n o que todos la aborten. En este protocolo, cuando la aplicacidn solicita que la transaction sea aceptada, el gestor de transacciones emite una solicitud de preparaci6n a todos 10s gestores de recursos implicados. Cada uno de estos recursos enviari una respuesta a su vez indicando si est6 preparado o n o para realizar su operacion. ~nicamente cuando todos 10s gestores de recursos estin preparados para aceptar, el gestor de transacciones emite una solicitud de commit a todos 10s gestores de recursos. D e n o ser asi, el gestor de transacciones emite una solicitud de deshacer y la transaccidn sera deshecha. El siguiente diagrama ilustra estas fases:

Capitulo 4
Las lineas de puntos indican el proceso de preparacidn durante el cual cada gestor de recursos manifiesta su voluntad de aceptar. Despuks de que todos 10s gestores de recursos indiquen que estin preparados para aceptar, el gestor de transacciones emite la llamada de aceptar que aparece en el diagrama con una linea continua. iC6mo puede el gestor de recursos o el gestor de transacciones solicitar deshacer la operacidn cuando la aplicacion ha decidido que la transaccidn debe ser aceptada? Esto puede pasar, por ejemplo, cuando uno de 10s recursos que participan en la transaccidn no es alcanzable debido a fallos en la red o en el sistema. Esto tarnbikn podria ocurrir si uno de 10s recursos que bloquea ciertos datos ya no puede mantener el bloqueo debido a una expiracidn del plazo. La fase de aceptacidn en dos fases certifica que cada recurso participante puede realrnente aceptar y realizar la transaccidn. El protocolo bifisico de aceptacidn tiene sus limitaciones. Por ejemplo, no puede recuperarse de casos en 10s que un gestor de recursos ha indicado que esti preparado para aceptar, per0 no ha conseguido aceptar (debido a fallos internos). En este caso, 10s recursos que se aceptaron con anterioridad a este fallo no pueden ser deshechos. Una situacidn similar surge cuando hay un fallo en la red durante el proceso de aceptacidn.

Construccion de bloques de sistemas de procesamiento de transacciones


Cualquier arquitectura tipica de procesamiento de transacciones irnplica un gestor de transacciones y gestor de recursos para cada recurso. Estos cornponentes abstraen la rnayoria de 10s temas especificos de transacciones de las aplicaciones y cornparten la responsabilidad de irnplernentacidn de transacciones.

Componentes de aplicacion
Los componentes de aplicacidn son clientes para 10s recursos transaccionales. ~ s t o son s 10s prograrnas con 10s que el desarrollador de aplicaciones implements las transacciones de ernpresa. Con la ayuda del gestor de transacciones, estos componentes crean transacciones globales, propagan el context0 de transaccidn si es necesario y operan sobre 10s recursos transaccionales dentro del alcance de estas transacciones. Estos componentes no son responsables de la implementacidn de la semintica para preservar las propiedades A C I D de las transacciones. Corno parte de la 16gica de aplicacidn, estos cornponentes generalmente deciden si aceptar o deshacer las transacciones. Las siglas A C I D representan Atomic (atdmico), Consistent (consistente), Isolated (aislado) y Durable (duradero). Las siguientes son las responsabilidades habituales de un cornponente de aplicaci6n:

o Crear y demarcar transacciones


0

Propagar contextos de transacciones Operar sobre datos mediante gestores de recursos

Gestores de recursos
U n gestor de recursos es un cornponente que gestiona sistemas de almacenamiento de datos estables y persistentes, y participa en 10s protocolos bifisicos de aceptaci6n y recuperacidn junto con el gestor de transacciones. Los ejemplos son sisternas de bases de datos, colas de mensajes, etc. \Adernis, un gestor de recursos es norrnalmente un driver o un envoltorio sobre un sistema de almacenamiento, con interfaces que operan sobre 10s datos (para 10s componentes de aplicacidn). Este componente puede tarnbih registrar, directa o indirectamente, recursos con el gestor de transacciones de

Programacion de bases de datos con J DBC


mod0 que el gestor de transacciones puede registrar todos 10s recursos que participen en una transacci6n. Este proceso se denomina alistamiento de recursos. El gestor de recursos tambikn debe implementar mecanismos suplementarios (por ejemplo, registro) que hagan posible la recuperaci6n. i o s gestores de recursos proporcionan dos grupos de interfaces: un grupo para que 10s componentes de aplicaci6n obtengan conexiones y ejecuten operaciones sobre 10s datos, y el otro grupo para que el gestor de transacciones participe en el protocolo bifisico de aceptaci6n recuperaci6n. Las siguientes son las tipicas re~~onsabilidades de 10s gestores de recursos:
0 Alistar recursos con el gestor de transacciones 0

Participar en el protocolo bifisico de aceptaci6n y recuperacibn

Gestor de transacciones
El gestor de transacciones es el componente central de un entorno de procesamiento de transacciones. Sus principales responsabilidades son crear transacciones cuando kstas sean solicitadas por 10s componentes de aplicaci6n, permitir el alistamiento y "delistamiento" de recursos, y ejecutar el protocolo de aceptaci6n/recuperaci6n con 10s gestores de recursos. Una tipica aplicaci6n transaccional empieza con la emisi6n de una solicitud a un gestor de transacciones para iniciar una transaccion. En respuesta, el gestor de transacciones inicia una transacci6n y la asocia con el hilo llamante. El gestor de transacciones tambiin establece un contexto de transacci6n. Todos 10s componentes de aplicacion y 10s hilos que participan en la transacci6n cornparten el contexto de transaccibn. El hilo que inicialmente emitib la solicitud para iniciar la transacci6n, o, si el gestor de transacciones lo permite, cualquier otro hilo, puede finalmente completar la transacci6n emitiendo una solicitud de aceptar o deshacer. Antes de que sea completada una transaccion, cualquier numero de componentes y/o hilos puede ejecutar operaciones transaccionales obre cualquier numero de recursos transaccionales conocidos para el gestor de transacciones. Si el gestor de transacciones lo permite, una transacci6n puede ser suspendida y despuis retomada antes de ser completada finalmente. Una vez que la aplicacidn emite la solicitud de aceptar, el gestor de transacciones prepara todos 10s recursos para una operaci6n de aceptaci6n (dirigiendo un voto) y, basindose en la situaci6n de 10s recursos (si estin o no preparados), emite una solicitud de aceptar o deshacer. Las siguientes son las tipicas responsabilidades de un gestor de transacciones:
0

Establecer y mantener el contexto de transacci6n

O Mantener la asociaci6n entre una transacci6n y 10s recursos participantes 0 0

Iniciar y dirigir el protocolo bifisico de aceptaci6n y recuperacidn con 10s gestores de recursos Realizar llamadas de sincronizacidn a 10s componentes de aplicaci6n antes de iniciar y despuis de finalizar el proceso bifisico de aceptaci6n y recuperacibn.

Transacciones distribuidas JDBC


Gracias a la secci6n anterior, ha quedado claro que el apoyo de las transacciones distribuidas es una necesidad absoluta para construir aplicaciones distribuidas de empresa. Debido a J2EE es una tecnologia destinada a construir tales aplicaciones, JDBC incluye apoyo a transacciones distribuidas. El apoyo a las transacciones distribuidas en JDBC especifica las responsabilidades de un driver de base de datos (equivalente a un gestor de recursos en el examen anterior).

Elpaquetejavax.sqlincluyedosinterfaces:j a v a x . s q l .D a t a S o u r c e y j a v a x .s q l . X A C o n n e c t i o n .
Observe que, por la convenci6n seguida por el modelo X/Open DTP, las interfaces que comienzan con las letras "XA" representan las interfaces p a r a s s t o r e s de recursos, es decir, drivers de base de datos o servidores de aplicacion que se ajustan a transacciones distribuidas.

La interfaz javax.sqlXADataSource
Esta es una fuente de datos transaccional. Esta interfaz es una factoria para objetos j a v a x . s q l . X A C o n n e c t i o n , y es similaralainterfaz j a v a x . s q l . D a t a S o u r c e . Sinembargo, enlugar de crear objetos j a v a x .s q l .C o n n e c t i o n , una implementaci6n de esta interfaz crea objetos j a v a x . s q l .X A C o n n e c t i o n . j a v a x . s q l .X A C o n n e c t i o n e s unainterfaz~onnectiontransaccional. Los siguientes son 10s rnetodos clave de esta interfaz:
public public javax.sql.XAConnection getXAConnection() throws java.sql.SQLException javax.sql.XAConnection getXAConnection (String user, String password) throws java.sql.SQLException

Los metodos restantes de esta interfaz son 10s mismos que 10s de la interfaz j a v a x . s q l .D a t a S o u r c e .

La interfaz javax.sqlXAConnection
Esta interfaz proporciona apoyo a las transacciones distribuidas. Esta interfaz amplia la interfaz j a v a x .s q l P o o l e d C o n n e c t i o n y naturalmente apoya todos 10s metodos especificados en la interfaz j a v a x .s q l .~ o o l e d ~ o n n e c t i o n . A d e m deestosm6todos, is lainterfazj a v a x . s q l .X A C o n n e c t i o n especifica el siguiente metodo adicional:

public

javax.transaction.xa.XAResource getXAResource() throws java.sql.SQLException

? C u l l es el prop6sito de este metodo? Para comprender rnejor el objetivo de este metodo, consideremos 10s conceptos de procesamiento de transacciones exarninados en la secci6n anterior. .&os componentes de aplicaci6n en transacciones distribuidas pueden acceder a 10s datos a traves de undtiples conexiones de bases de datos. Es decir, una transaction consiste en diversas conexiones, con cada conexi6n operando (leyendo, actualizando o eliminando) en un determinado conjunto de recursos de base de datos. C o m o hemos visto en la secci6n anterior, cada recurso debe ser alistado, de modo que el gestor de transacciones pueda registrar todos 10s recursos que hayan podido ser rnodificados durante la transacci6n. El JTA especifica la interfaz j a v a x . T r a n s a c t i o n . x a .X A R e s o u r c e para este propbsito. Para cada objeto c o n n e c t i o n , el gestor de transacciones obtiene un j a v a x . T r a n s a c t i o n - x a .XAResourcey~oa~istaen~atransacci6nactua~. El paquete j a v a x . t r a n s a c t i o n . x a es una parte del API JavaTransaction (JTA). Antes de continuar para analizar corn0 podemos implementar transacciones distribuidas, debemos considerar una interfaz adicional.

La interfaz javax.Transaction.UserTransaction
La demarcaci6n de transacciones programiticas se lleva a cab0 con el uso de la interfaz U s e r T r a n s a c t i o n .
~ s t es a innecesaria en entornos controlados por contenedor como contenedores EJB. Esta interfaz n o forma parte de JDBC per0 si del API Java Transaction (JTA). Podemos acceder a este API online en http://java.sun.com/products/jta/javadocs-1.0.Yindex.html.

Programacion de bases de datos con JDBC


La interfaz U s e r T r a n s a c t i o n encapsula la mayorparte de la funcionalidad de un gestor de transacciones y son 10s vendedores de servidores de aplicaci6n (o software intermediario transaccional) quienes deben implementarla. Los mttodos expuestos por esta interfaz proporcionan 10s medios para iniciar y finalizar transacciones explicitamente:
public void begin() throws NotSupportedException, SystemException

Con la ayuda de este metodo, podemos crear una nueva transacci6n. ~ oS ut p p o r t e d E x c e p t i o n y ~~ste~xce~tionsonpartedelpaq ju av ea tx e t r a n s a c t i o n . Laexcepcion Not S u p p o r t e d E x c e p t i o n es lanzada cuando el gestor de transacciones no puede iniciar una transacci6n. ejemplo, esto puede ocurrir si estuvitramos intentando iniciar una segunda transaccion dentro del mismo hilo. La exception s y s t e m E x c e p t i o n es lanzada en caso de errores inesperados.

public void commit()

throws RollbackException, HeuristicMixedException, HeuristicRollbackException, java.lang.SecurityException, java.lang.IllegalStateException, SystemException

commit ( ) acepta explicitamente todas las operaciones de base de datos ejecutadas hasta el momento en la transaccion actual. El gestor de transacciones subyacente utiliza el proceso bifisico de aceptacion y recuperaci6n para completar el proceso de aceptacion.
public void rollback() throws java.lang.IllegalStateException, java.lang.SecurityException, SystemException

Podemos utilizar este metodo para deshacer la transacci6n actual. De 10s tres mttodos anteriores, el primero marca el inicio del limite de una transaccion, mientras que el segundo y tercer metodo finalizan explicitamente una transacci6n. Estos mttodos son utilizados en la demarcaci6n explicita de transacciones.
public void setRollbackOnly() throws java.lang.IllegalStateException, SysemException

s e t ~ o l l b a kOnl c y ( ) permite a una aplicaci6n aplicar deshacer y la transacci6n no,debe ser aceptada desde ese momento. Desputs de invocar este mttodo, si intentamos invocar el metodo commit ( ) anterior, laaplicaci6n recibirilaexcepci6n j a v a x . T r a n s a c t i o n . R o l l b a c k E x c e p t i o n .
public int getstatus() throws SystemException

Este mttodo devuelve el estado actual de la transacci6n. Estos valores de estado estin definidos en la interfazjavax. T r a n s a c t i o n . S t a t u s .
public void setTransactionTimeout(int seconds) throws SystemException

Podemos especificar el intervalo de plazo de tiempo miximo para la transacci6n con s e t T r a n s a c t i o n T i m e o u t ( ) . Esto permite a1 gestor de transacciones reclamarla transaccion pendiente y deshacer todos 10s cambios en caso de que el cliente siga inactivo mis alli de este intervalo.

Pasos para la implernentacion de transacciones


Los siguientes pasos son necesarios para la demarcaci6n programitica de transacciones. En transacciones controladas por contenedor (declarativas), el h i c o paso a seguir es la configuraci6n.

Capitulo 4

El primer paso es configurar el senidor de aplicaci6n y el driver de base de datos, siguiendo el procedimiento descrito por su senidor de aplicaci6n. Similares a la interfaz javax.sql .ConnectionPoolDataSourceyjavax. sql.PooledConnection,~asdosinterfaces anteriores deben ser implementadas por vendedores de senidor de aplicaci6n y vendedores de driver de base de datos. Por lo tanto, el entorno de senidor de aplicaci6n debe ser configurado para utilizar la interfaz javax .sql .XADataSource. Sin embargo, la mayoria de vendedores de senidor de aplicaci6n J2EE tienen sus propias implementaciones de este API, en cuyo caso puede no ser necesario que realicemos esta configuraci6n.

lniciar una transaccion


Para iniciar una transacci6n, debemos obtener una objeto que implemente la interfaz javax .Transaction.UserTransaction. El enfoque estindarpararecuperar este objeto es ejecutar una busqueda en el servicio JNDI. El siguiente fragmento de c6digo ilustra esta situaci6n:
import j avax. sql. *; import javax.naming.*; import javax. transaction.*;
// // //

Import th'e javax.sq1 package Import the JNDI API Import the JTA

try I Context initialcontext = new Initialcontext(); UserTransaction ut = (UserTransaction) ) ; n" initialcontex. lookup ("javax.t r a n ~ a ~ t i ~ n . U s e r T r a n s a c t i o ut.begin (
)

I
Fijese en que importamos elpaquete javax .Transactionademis de 10s paquetes j avax .sql y javax .naming. En el fragmento anterior, la bGsquedade J N D I busca j avax .Transaction.UserTransaction.~ s t es e el nombre estindar asociado a la interfaz j avax .Transaction.UserTransaction.El senidor de aplicaci6n, que implementa esta interfaz, asocia un objeto que implementa esta interfaz en el servicio JNDI.

Operaciones de base de datos


Aparte de ciertas restricciones sobre la invocaci6n de determinados mCtodos sobre el objeto j ava .sql .Connect ion,el resto del procedimiento para la busqueda de J N D I de un objeto de fuente de datos, para crear conexiones, y ejecutar instrucciones SQL, es el mismo. El siguiente fragmento de c6digo no ofrece una instantinea:
DataSource datasource UserTransaction ut
=
=

null; null;

. ..

//

Crear un context0

try I Context context = new Initialcontext ( ) ; datasource = (DataSource) context.lookup("jdbc/x"); ut = (UserTransaction) context.lookup("javax.transaction.UserTransaction"); ] catch (NamingException ne) {

Programacion de bases de datos con JDBC


//
Error a1 crear el contexto o e r ~l a b6squeda.

1
Connection connection
=

dataSource.g,etCor~r~ectio ( ) r~ ;

//

Ejecutar

operaciones

de

base

de datos

habituales

/ / D e s h a c e r l a t r a n s a c c i b n e n c a s e d e c u a l q u i e r f a l l o d e c o n d i c i b n d e ernpresa
if(...){ / / Obtener l a UserTransaction. u t . setRollbackOnly ( )

// //

R e a l i z a r algo que u t i l i c e objeto d e conexibn doSorneThing();

otra

fuente

de datos

y otro

El c6digo anterior realiza operaciones sirnilares a las que realizariamos en transacciones de base de datos. Sin embargo, la implementaci6n de la 16gica de aplicaci6n puede decidir producir una condici6n para deshacer la transacci6n. Veamos quC ocurre cuando invocamos el metodo g e t c o n n e c t i o n ( ) en la fuente de datos. C o n nuestro servidor de aplicaci6n configurado para transacciones distribuidas, el objeto de fuente de datos utiliza la implementaci6n subyacente de la interfaz j a v a x .s q l .X A D a t a S o u r c e para crear objetos j a v a x . s q l .X A C o n n e c t i o n . F i j e s e e n q u e u n X A C o n n e c t i o n e s u n tipoespecialde P o o l e d C o n n e c t i o n (ja v a x s q l ~~~onnectionamplialainterfaz j a v a x . s q l . P o o l e d C o n n e c t i o n ) . D a t a S o u r c e , p o r l o tanto, obtieneunaconexion deesteobjeto j a v a x s q l .XAConnectioninvocandoelm~todogetConnectionyla devuelve alaaplicacidn. Observe que esto es exactamente lo que sucede con la reserva de conexiones.

Hay un paso adicional: el alistamiento de recursos. Antes de devolver una c o n e x h , el gestor subyacente ony de transacciones obtiene el objeto j a v a x .t r a n s a c t i o n . X A R e s o u r c e d e ~ ~ ~ o n n e c t l alista recursos parala transacci6n. Los paquetes j a v a x . t r a n s a c t i o n y j a v a x . t r a n s a c t i o n . x a cuentan con otros paquetes que asisten en el alistamiento de recursos y e n el proceso bifisico de aceptaci6n y recuperaci6n. Sin embargo, como desarrollador de aplicaciones, s61o nos interesa la interfaz javax.transaction.UserTransaction.

Finalizar una transaccion . El procedimiento para finalizar una transacci6n es similar el mod0 en el que iniciamos una transacci6n.
Ahora invocamos el metodo c o m m i t ( ) en el objeto U s e r T r a n s a c t i o n para finalizar la transacci6n. Puede que necesitemos realizar una blisqueda JNDI adicional para recuperar el o b j e t o u s e r T r a n s a c t i o n si la transaccidn se e s t i cerrando desde un mitodo u objeto diferente a1 que inici6 la transacci6n.

Precauciones especiales
En una transacci611, no se pueden ejecutar las siguientes operaciones:

Capitulo 4
0 N o debemos invocar 10s mktodos c o m m i t ( ) y r o l l b a c k ( ) en objetos c o n n e c t i o n . Esto se

debe a que el objeto de transacci6n de usuario controla 10s limites de la transacci6n. Estos mktodos lanzan la excepci6nj a v a .s q l .S Q L E x c e p t i o n cuando son invocados en una transacci6n.
0

N o debemos permitir la autoaceptaci6n (auto-commit) en objetos c o n n e c t i o n . Observe que auto-commit es contrario a la noci6n de transacciones. Cuando recuperamos una conexi6n bajo una transacci6n, la conexitin tendri auto-commit desactivado por defect0 y si intentamos activarlo (i )t ,lanzalaexcepci6n j a v a .s q l .S Q L E x c e p t i o n . invocando el m k t o d o s e t ~ u t o ~ o m m

Objetos RowSet
El rasgo final del paquete j a v a x . s q l que analizaremos es el objeto ow set. En tkrminos sencillos un rowset (grupo de filas) es un componente que se ajusta a JavaBean que encapsula el acceso a base de datos incluido el resultado. La interfaz j a v a x s q l RowSet representa la funcionalidad bisica para un rowset. Para comprobar 10s beneficios de utilizar un rowset, consideremos un simple acceso a bases de datos para tomar un grupo de filas. Veamos primer0 c6mo conseguiriamos esto sin utilizar un rowset:

/ / Crear una conexi6n connection = DriverManager.getConnection("jdbc:cloudscape:Movies"); connection.setAutoCommit(fa1se); / / Crear una conexi6n Statement statemer~t = connection. createstatemento ; / / Ejecutar una consulta ResultSet rs = statemer~t.executeQuery("SELECT *

FROM CATALOG");

while(rs.next0) { / / Desplazar y procesar 10s resultados

I
En este enfoque, hay a1 menos tres objetos que representan diferentes aspectos de una operaci6n de busqueda: un objeto j a v a .s q l c o n n e c t i o n para conectividad de base de datos, un objeto j a v a . s q l . S t a t e m e n t paraejecutarunainstrucci6n y unobjeto j a v a . s q l . R e s u l t s e t paraalbergar 10s valores devueltos.

En su lugar, consideremos un enfoque en el que la misma operaci6n de consulta sea encapsulada por un tinico objeto:
JdbcRowSet rowset
=

new JdbcRowSet

( ) ;
=

rowset. setcommand ("SELECT * FROM CATALOG WHERE TYPE rowSet.setUrl("jdbc:clouscape:Movies"); rowset. setusername ( " s a " ); rowset. setpassword ("") ; rowSet.execute( ) ; while(rowSet.next()) { / / Desplazar y procesar 10s resultados

'ROMANCE' " ) ;

I
El c6digo anterior ilustra una posible aplicaci6n de objetos RowSet. En este c6dig0, esta clase JdbcRowSe t es parte del paquete s u n . j d b c .r o w s e t. Este paquete es una implementaci6n de referencia

Programacion de bases de datos con JDBC


de la especificacion RowSe t.Puede descargarla junto con ejemplo en http://developer.java.sun.corW developer/earlyAcce~~.~cis/'. Aparte de esta encapsulation, la principal caracteristica de un grupo de filas es que un objeto rowset puede utilizarse como componente JavaBean. Como bean, un RowSet proporciona un conjunto de mutadores para establecer propiedades y un grupo complementario de accesores para obtener 10s valores de esas propiedades. En el ejemplo anterior, invocamos programiticamente 10s configuradores para configurar las propiedades del rowset. En su lugar,,podriamos utilizar un entorno de programacion visual para crear un objeto ROWS e t y establecer sus prop~edades. Los objetos r ow set tambien se ajustan a 10s eventos de estilo JavaBean. Los objetos Rowset generan eventos cuando tienen lugar ciertos cambios en el estado del grupo de filas. Los objetos interesados pueden registrarse como escuchantes para estos eventos y que les sea notificado a medida que van sucediendo 10s eventos.

E n esencia, u n objeto RowSet es u n componentes JavaBeans; tiene ciertas propiedades que pueden y una serie de eventos que pueden escuchar 10s objetos ser manipuladas por ~onfi~uradores interesados. U n objeto RowSet tambie'n encapsula 10s resultados de ejecutar una instruccidn.
La interfaz j a v a x s ql .ROWS et puede ser implementada como una capa separada encima de una capa JDBC existente. La implementacion de referencia de Sun es de hecho una capa de este tipo y podemos utilizarla encima de cualquier driver JDBC que se adapte a JDBC 2.1.

La interfaz javax.sql.RowSet
public interface RowSet extends java.sql.Resu1tSet

La interfaz j a v a x . sql .RowSet amplia la interfaz j a v a . sql .ResultSet. Estose debe aque un rowset tambien encapsula un grupo de filas (resultados) separados de las propiedades. Como hemos visto, la interfaz j a v a .sql .ResultSet ofrece un rico espectro de mttodos para acceder a filas de resultados. Por 10 tanto, todos 10s metodos que son aplicables para una lista de resultados lo son tambien para un grupo de filas (rowset).

Propiedades
La interfaz j a v a x . sql RowSet proporciona una serie de propiedades JavaBeans que pueden ser fijadas en el periodo de diseiio. C o n la ayuda de estas propiedades, el objeto ROWS et puede conectar a una fuente de datos y recuperar una lista de resultados en el periodo de ejecucion. Los siguientes son algunos de 10s parimetros comunmente requeridos:
0

URL: un URL JDBC.

0 Nombre de fuente de datos: Nombre de la fuente de datos. Dependiendo de la implementacion, el grupo de filas puede utilizar bien un URL o bien un nombre de fuente de datos para obtener una conexion. 0 Nombre de usuario: Nombre de usuario para obtener una conexion.

Contraseiia de usuario: Contraseiia para obtener una conexion.


$0 Aislamiento de transaccibn: Nivel de aislamiento de transaction. ~ s t es a una propiedad de j a v a . s ql Connect ion que especifica un conjunto de constantes para nivel de aislamiento.

0 Comando: La instrucci6n SQL. El comando tambien puede ser un string de instrucciones preparadas.

Capitulo 4 Eventos
Los objetos RowSet pueden generar tres tipos de eventos:
O Eventos de movimiento de cursos: estos son generados cuando el cursor es desplazado. Por

ejemplo, invocar un mktodo p r e v i o u s

()

en el objeto RowSet generaria un evento.

O Eventos de carnbio de fila: estos eventos son generados cuando las filas de un grupo de filas son

alteradas. Por ejemplo, eliminar una fila generaria un evento.


O Eventos de carnbio de grupo de filas: estos eventos son generados cuando todos 10s contenidos del grupo

de filas cambian. Por ejemplo, evocar e x e c u t e


javax.sq1.RowSetListener:

()

cambiaria el contenido completo de un grupo de filas.

Para que 10s objetos de aplicaci6n Sean notificados de estos eventos, el API JDBC especifica la interfaz
public interface RowSetListener extends java.util.EventListener

Esta interfaz especifica tres mCtodos:


public void cursorMoved(RowSetEvent event) public void rowChanged(RowSetEvent event) public void rowSetChanged(RowSetEvent event)

El objeto RowSet invoca estos mktodos cuando tiene lugar uno de 10s eventos enumerados. Los objetos de aplicaci6n que implementan la interfaz j a v a x .s q l .ROWS e t ~i s t e n e r pueden registrar y "desregistrar" estos eventos con rowset, utilizando 10s siguientes mktodos en j a v a x .s q l . RowSet:
public void addRowSetListener(RowSetListener listener); public void removeRowSetListener(RowSetListener listener);

Estos mktodos son similares a 10s que encontramos en AWT y Swing. Podemos afiadir dinimicamente mis de un escuchante. Tambikn podemos eliminar estos escuchantes dinimicamente. Cuando 10s objetos L i s t e n e r s (escuchantes) son notificados, reciben el objeto ROWS e t encapsulado en javax.sql.RowSetEvent.

Ejecucion de comandos y resultados


DespuCs de establecer las propiedades y 10s escuchantes, podemos invocar el metodo execute() en el grupo de filas para poblar 10s resultados y utilizar cualquiera de 10s mCtodos especificados en la interfaz j a v a . s q l .R e s u l t s e t para desplazar y modificar 10s resultados. El mktodo e x e c u t e ( ) obtiene -)internamente una conexi6n de base de datos, prepara una instruccih y crea una lista de resultados. Crear y utilizar 10s objetos RowSet es muy sencillo y sigue el modelo JavaBeans. Para poblar una lista de resultados, hay tres tareas que es precis0 realizar:
O Crear un objeto RowSet

o Configurar sus propiedades


0 Ejecutarlo

Tipos de objetos RowSet


El API JDBC no especifica interfaces estindar que implementen la interfaz j a v a x .s q l .RowSet. La entrega de primer acceso de Sun, sin embargo, identifica tres posibles implementaciones. Aunque en la

Programacion de bases de datos con J DBC


actualidad estas no forman parte de la especificaci6n, en el futuro podrian ser axiadidas a la especificaci6n como parte de una serie de interfaces revisadas. Las siguientes son tres posibles implementaciones de esta interfaz:

O Rowsetscache (sun.jdbc.rowset.~achedRowSet) O Rowsets JDBC (sun.jdbc . rowset. JdbcRowSet)


Estas implementaciones estin especificadas en el paquete sun. jdbc . rowse t,que no forma parte del API JDBC . En la actualidad, Sun ofrece una implementaci6n de referencia de estos objetos RowSet en una entrega Early Access (en la actualidad, entrega 4), que puede ser descargada de la pigina Web de Sun Java Developer Connection (http : / / java .sun.corn/jdbc/). Esta entrega de primer acceso incluye implementaciones de estos tres tipos de objeto Rowset. Todas las clases anteriores se extienden desde sun.jdbc . rows et .BaseRows et e implementan la interfaz javax . sql .RowSet. La clase BaseRowSe t proporciona la implementaci6n com6n para propiedades, eventos y mktodos para establecer parimetros para objetos RowSe t (puesto que 10s objetos rowset implementan la interfaz j ava .sql .ResultSet). Aparte de la implementaci6n de referencia, algunos de 10s vendedores de drivers JDBC estin empezando a apoyar las implementaciones para estos tipos de Rowset.Si desea una lista de drivers que se ajusten a rowset, visitehttp://industry.java.sun.co~products/jd bcldrived. En las siguientes subsecciones, analizaremos brevemente cada una de estas implementaciones Rowset.

La implernentacion CachedRowSet
Una lista de resultados JDBC es un objeto conectado. Es decir, siempre que la Iista de resultados este abierta (y antes de que invoquemos el metodo close ( ) sobre ella), la lista de resultados mantiene una conexi6n con la base de datos. Esto es aceptable si mantuvieramos la lista de resultados en cortos intervalos. Sin embargo, cuando pretendemos utilizar 10s objetos ResultSet para periodos significativos de tiempo, mantener la conexi6n consumiri niveles inaceptables de recursos de red. Por ejemplo, si una lista de resultados tiene 1000 filas y la aplicaci6n Web esti presentando 10 resultados por pigina, puede que necesitemos mantener el objeto connect ion durante un marco de tiempo significativamente largo. Esto no es deseable. Para atajar este problema, tendriamos que transferir 10s resultados a objetos de adaptaci61-1,de mod0 que podamos liberar la instrucci6n y la conexidn inmediatamente despues de ejecutar la instrucci6n. El rowset cache trata este problema. Una vez ha sido creado el rowset cache y 10s resultados han sido poblados, la instrucci6n y 10s objetos connect ion pueden ser cerrados. El rowset cache mantiene las filas de resultados de forma "desconectada". Cuando actualizamos o modificamos el RowSe t,el rowset cach6 conecta con la base de datos y ejecuta las actualizaciones en la base de datos y, por lo tanto, limita el coste de recursos. t Laclasesun. j dbc .rowset.CachedRowSet d e f i n e u n ~ o w s e cache.
public class CachedRowSet extends BaseRowSet implements javax.sql.RowSet, javax.sql.RowSetInterna1, java.io.Serializable, java.lang.Cloneable

U n rowset cache es un contenedor para filas de datos desconectado, serializable, clonable y desplazable. Ampliasun. j dbc . rowset. CachedRowSet eimplementalasinterfaces javax. sql .RowSet,

Capitulo 4
R o w S e t I n t e r n a l , j a v a . i o . S e r i a l i z a b l e y j a v a . lang.cloneable.Estidesconectadoy,por lo tanto, no alberga un objeto c o n n e c t i o n . Puesto que es serializable y clonable, podernos crear copias de nuestro rowset cache y transferirlas por la conexi6n. Por ejernplo, un cornponente EJB puede crear y devolver un rowset cache a un cliente en la red. El cliente puede rnodificar el ROWS e t y enviarlo de vuelta al cornponente, y el cornponente puede realizar actualizaciones. Para que las aplicaciones poblen y accedan rnodifiquen el estado de un rowset cache, el rowset cache tarnbien irnplernenta la interfaz javax.rowset.RowSetInternal. El objeto C a c h e d R o w S e t es apropiado para dos escenarios corno rninirno: La aplicacidn cliente pretende rnantener 10s resultados durante un interval0 de tiernpo significativarnente largo. Esto es asi para las aplicaciones Web asi corno para las aplicaciones cliente-servidor que ejecutan consultas con un nlirnero de filas de resultados posiblernente alto.
O

El cliente no tiene ni la capacidad ni 10s recursos para conectar con una base de datos. Por ejernplo, 10s dispositivos redificados corno PDA y otros clientes infradotados no tienen 10s recursos necesarios para conectar con bases de datos. En estos casos, una aplicacidn de lado servidor puede crear un rowset cache y enviarlo por la red al cliente infradotado. El cliente puede desplazar el rowset y puede tarnbien guardarlo para un uso posterior. El cliente puede enviar una copia de 10s resultados de vuelta a la aplicaci6n de lado servidor siernpre que la actualice.

En efecto, el rowset cache nos proporciona la capacidad para crear listas de resultados "descargables". El procedimiento para crear y utilizar un rowset cache es similar a1 que hernos visto a1 principio de esta secci6n:
CachedRowSet rowSet
=

new CachedRowSet

( ) ;

rowset. setCommand ("SELECT * FROM CATALOG WHERE TYPE = rowSet.set~rl("jdbc:cloudscape:Movies;create=true"); rowSet.setUrl("jdbc:cloudscape:Movies"); rowset. setusername ( " s a " ); rowSet.setPassword(""); rowset. execute ( ) ; while(rowSet.next()) [ / / Desplazar 10s resultados.

'ROMANCE'

"

) ;

i
El rowset cache se puebla cuando se invoca el rnetodo e x e c u t e ( ) Los rnetodos updateXXX ( ) son 10s especificados en la interfaz j a v a . s q l . R e s u l t S e t y estin destinados a listas de resultados actualizables. Puesto que el rowset cache esti desconectado, la base de datos no aplica ninglin control de concurrencia en 10s datos albergados por el rowset cache. Para rnantener una concurrencia bptirna, la irnplementacidn actual de un rowset cache cachetiza el valor original de 10s datos. Esta copia representa el estado del rowset cache cuando se invoca el metodo e x e c u t e ( ) . Podemos acceder a 10s datos originales invocando . rnetodos 10s rnetodos g e t o r i g i n a l ( ) y g e t O r i g i n a l R o w ( ) sobre el o b j e t o c a c h e d ~ o w s e tEstos devuelven objetos ~ e s u ls te t que se corresponden con el rowset cache y la fila actual respectivarnente. Puesto que el rowset esti desconectado, debemos invocar el metodo a c c e p t c h a n g e s ( ) para actualizarel rowset:

Este metodo restablece una conexidn con la base de datos y realiza las actualizaciones necesarias a la base de datos. Si 10s datos originales albergados en CachedRowSet no coinciden con 10s datos de la base de datos, este rnetodo no actualiza la base de datos con 10s valores carnbiados. Observe que este rnetodo lanza la excepci6n S Q L E x c e p t i o n en caso de fallos a1 efectuar 10s carnbios.

Procramacion de bases de datos con JDBC

La implementacion RowSet JDBC


El rowset JDBC es un rowset conectado. El objetivo del rowset JDBC es proporcionar una capa tip0 JavaBeans encima de j a v a .s q l .~ e s u lset. t Esti definida en la clase
sun.jdbc.rowset.JdbcRowSet:
public class JdbcRowSet extends BaseRowSet implements javax.sql.RowSet

En esta especificaci6n de clase, a diferencia de un rowset cache, un rowset JDBC esti conectado, n o e s serializable y no es clonable. Proporciona las caracteristicas que proporcione la interfaz subyacente j a v a .s q l . R e s u l t s e t , con la ventaja aiiadida de presentarse a si misma como un JavaBean.

La implementacion RowSet Web


.

En el momento de escribir este libro, la especificaci6n rowset no es definitiva y la implementacion esti siendo distribuida como entrega de primer acceso. La implementaci6n de la entrega de primer acceso no esti completa en si misma. En esta seccibn, vamos a centrarnos por lo tanto en 10s conceptos que se encuentran detris del rowset Web, sin entrar en detalles de programaci6n. El siguiente apartado representa la estructura deseada de este tip0 rowset. El rowset Web esti destinado a aplicaciones de base Web. Por este motivo, el mod0 primario en que se desvia del rowset cache (que amplia) esti en que se comunica con otros componentes mediante el uso de XML sobre HTTP. La clase t. s u n . j d b c .r o w s e t .WebRowS e t representa una implementaci6n cliente-sewidor de la i n t e r f a z ~ o w s e
public class WebRowSet extends CachedRowSet

Se espera que la implernentaci6n rowset Web incluya la clase anterior, un senlet Java y un protocolo para transmitir datos tabulares utilizando XML como formato de datos. La situaci6n ideal para utilizar un rowset Web es la siguiente: un cliente Web (posiblemente con apoyo Java o JavaScript) recupera una lista de resultados utilizando un objeto s u n . o d b c . r o w s e t . WebRowSet. Cuando se invoca el metodo e x e c u t e ( ) en el rowset Web, invoca un sewlet en el lado sewidor (que ejecuta el acceso a la base de datos) para poblar una lista de resultados. Una vez es actualizado el rowset, el objeto WebRowSet envia 10s datos actualizados a una implementaci6n de lado sewidor del rowset como datos XML sobre el protocolo HTTP. La implementacidn de lado sewidor actualiza entonces la base de datos. Los objetos WebRowSet utilizan cachetizacion incremental de datos, de mod0 que 10s datos pueden ser recuperados en fracciones desde el lado sewidor. Mientras el cliente navega por el rowset Web, algunos datos adicionales son descargados desde el lado servidor. Aunque la especificacion y la implementaci6n de esta clase estin actualrnente incompletas, el objetivo de esta c l a s e ~ e b ~ o wes ~e eltsiguiente. En Internet, no siempre es posible conectar a un sewidor de base de datos. Los proxys y 10s cortafuegos a rnenudo no lo permitirin. Incluso si las configuraciones de proxy/cortafuego lo permite, abrir una base de datos en Internet supone una amenaza a la seguridad. Para evitarlo, la implementacibn de lado servidor del rowset Web actuari como proxy para la base de datos. Por lo tanto, la implementaci6n de lado cliente utiliza la implementacion de lado sewidor para recuperar y actualizar resultados. La principal implicacidn de esta arquitectura es que convierte a 10s clientes de base de datos en infradotados y 10s clientes pueden utilizar el protocolo H T T P (en lugar de protocolos de base de datos basados en TCP/IP). Cuando el cliente Web crea una lista de resultados Web y ejecuta un comando, la implementacibn del lado cliente del rowset Web envia esta solicitud a la irnplementaci6n de lado sewidor sobre HTTP. La implementacibn de lado sewidor conectari con la base de datos, ejecutari el comando y poblari el

Capitulo 4
Rowset. La implementaci6n de lado servidor escribiri entonces 10s datos en un documento XML y 10s enviari de vuelta a la implementacibn de lado servidor sobre HTTP.

Este proceso se repite cuando el cliente modifica el rowset e invoca acceptchanges ( ) . La implernentaci6n de lado cliente enviari una copia XML del rowset Web a la implementaci6n de lado servidor sobre H T T P y la implementacidn de lado servidor realizari las actualizaciones. Este mecanismo cuenta con HTTP y XML para el intercarnbio de comandos y datos entre implementaciones de lado cliente y de lado servidor. Esto elimina la necesidad de que el cliente conecte con el servidor de base de datos en Internet. Basindonos en este enfoque, podemos esperar implementaciones rnis refinadas para clientes infradotados.

Resumen
El prop6sito de este capitulo ha sido proporcionar un andisis de la programacion de bases de datos utilizando el API JDBC e introducir entonces ciertos conceptos avanzados relacionados con transacciones y bases de datos que son rnis relevantes en una plataforma de empresa como J2EE. C o m o mencionamos a1 principio de este capitulo, el objetivo de la prirnera parte del capitulo ha sido analizar c6mo ejecutar tipicas operaciones SQL utilizando este API. El API JDBC es bastante extenso y ofrece rnis funciones de las que podemos cubrir en un capitulo. La mayoria de estas funciones (como 'actualizaciones de lotes, listas de resultados desplazables, etc.) son comparativamente nuevas y la mayoria de 10s vendedores de bases de datos s61o estin empezando a apoyar estas caracteristicas. Le hemos animado a que consulte la documentaci6n del vendedor antes de pensar en implernentar estas funciones. Para resumir, en la primera parte de este capitulo, hemos analizado 10s siguientes puntos:
0 Drivers de base de datos y c6mo cargar drivers JDBC 0 Crear tablas e insertar datos 0 Instrucciones preparadas
O

Representaci6n entre SQL y tipos Java Actualizaciones de lotes

0 Listas de resultados desplazables 0 Puntos de salvaguardia

En la segunda parte de este capitulo, hemos analizado cuatro funciones avanzadas del API JDBC:
0 Las aplicaciones cliente JDBC no necesitan estar cableadas para drivers JDBC especificos y para utilizar 10s U R L JDBC especificos de vendedor. En su lugar, el objeto Datasource, cornbinado con la asociacidn y bhsqueda de base JNDI, separa 10s detalles de base de datos especificos de vendedor de las aplicaciones de cliente.

O El paquete javaxsql traslada la responsabilidad de reserva de conexiones a 10s servidores de aplicaci6n J2EE y drivers JDBC. C o n este enfoque, la reserva de conexiones consiste s61o en configurar el servidor de aplicaci6n; no es necesario implementar reserva de conexiones de adaptacibn, ya que este mecanismo ofrece un medio rnis fiable de reserva de conexi6n.
0 El procesamiento de transacciones distribuidas nunca ha sido tan sencillo. Utilizando la interfaz j avax .Transact ion. ~ s e r ~ r a n s a c t i o n , p o d e r ndemar~arex~licitamente os transacciones, mientras todavia utilizamos el API JDBC estindar para acceso a bases de datos.

Programacion de bases de datos con JDBC


0 La interfaz RowSet y sus implementaciones son un complemento para el API JDBC. El objetivo

de RowSet es proporcionar un acceso a 10s datos rnis flexible, similar a bean. Sun tambikn esti estudiando 10s objetos de datos Java, Java Data Objects UDO), probablemente basados en 10s objetos de datos activos de Microsoft, Active Data Objects. Se espera que 10s J D O complementen el API JDBC y proporcionen acceso a base de datos a un nivel rnis alto sin utilizar SQL. El API JDBC esti en desarrollo en la actualidad, y podemos esperar funciones rnis avanzadas de acceso a datos en el futuro. Consulte las novedades en http://java.sun.com/products/jdbc/. En el siguiente capitulo analizaremos las aplicaciones Web y 10s contenedores que las gestionan.

Introduccion a 10s contenedores Web


Como hemos visto en el capitulo 1, hay fundamentalmente dos tipos de clientes en la arquitectura JZEE: clientes Web y clientes de aplicaci6n. Los clientes de aplicaci6n se remontan a la arquitectura clienteservidor tradicional en la que 10s clientes dirigen la interaccibn del usuario (normalmente via GUI), asi como la mayor parte de la 16gica de aplicaci6n (incluido el acceso a bases de datos):Por este motivo, 10s clientes de aplicacibn se conocen t a m b i h como clientes robustos. Los clientes robustos procesan la 16gica de aplicacibn de forma local. En una arquitectura multi-capa, 10s clientes de aplicaci6n pueden delegar parte de la 16gica de aplicacibn y acceso a bases de datos en 10s componentes de la capa media (como Enterprise JavaBeans). A pesar de esta distribucidn de la 16gica de aplicaci6n en 10s componentes de la ' capa media, 10s clientes de aplicaci6n autbnomos se mantienen robustos y requieren instalacion en cada instalaci6n de usuario. Con la llegada de Internet, 10s clientes Web sustituyeron a muchos clientes de apkaci6n aut6nomos. El principal motor de este cambio es la naturaleza de 10s clientes Web. En las arquitecturas basadas en clientes Web, la capa de interacci6n con el usuario esti separada de la capa de cliente tradicional. Los navegadores Web gestionan la interacci6n de usuario per0 dejan el resto alas aplicaciones del lado servidor, incluido la lbgica para controlar la interfaz de usuario, la interaccibn con 10s componentes de la capa media y el acceso a las bases de datos. Para un usuario final, el navegador es el cliente para todas las aplicaciones de base Web. Puesto que este tip0 de cliente de objetivo general no impone n i n g h requisito especial (aparte del acceso a la red) en la instalaci6n cliente, 10s clientes Web tambien son denominados clientes infradotados. Los siguientes rasgos caracterizan a 10s clientes Web habituales:
0

U n navegador Web o aplicaci6n similar gestiona la interaccibn de usuario; 6sta es la capa cliente. usuarlo.

U HTML (con JavaScript y/o DHTML) o XML (XSLT) es utilizado para crear la interfaz de

0 HTTP(S) es el protocolo de intercambio de informaci6n utilizado por clientes y aplicaciones. Los programas de aplicaci6n en el lado servidor ejecutan la 16gica de aplicaci6n en nombre de 10s clientes navegador.

La arquitectura J2EE ofrece un modelo de programaci6n flexible y rico en funciones para construir aplicaciones Web dinimicas. Como hemos visto en el capitulo 1, la arquitectura J2EE proporciona contenedores Web, el Java Sewlet API y Javaserver Pages API para la construcci6n y gesti6n de las aplicaciones Web. El contenedor Web ofrece el entorno basic0 de periodo de ejecucidn y un marco para proporcionar apoyo de period0 de ejecuci6n para 1as aplicaciones Web. El servlet Java y las tecnologias JSP forman el material central para el desarrollo de las aplicaciones Web. Este capitdo nos introduce en 10s contenedores Web de J2EE y en 10s principios bisicos del desarrollo de aplicaciones Web, en tres aspectos diferentes:
0 Analizaremos la anatomia bisica de un contenedor Web. Empezando con una breve introduccidn a HTTP, para despuks centrarnos en 10s conceptos de 10s contenedores Web, 10s servlets Java y las piginas JSP. Continuaremos conociendo estos temas en capitulos posteriores. 0 Haremos un recorrido por la creaci6n de una sencilla per0 completa aplicaci6n Web. 0 Analizaremos, en detalle, el funcionamiento interno de un ejemplo de aplicaci6n Web.

Comenzaremos examinando c6mo se comunican clientes y servidores utilizando el protocolo HTTP.

El protocolo HTTP
En el desarrollo de aplicaciones distribuidas, el protocolo de comunicacidn determina la naturaleza de clientes y servidores y la relaci6n entre ellos. Esto t a m b i h se cumple en el caso de aplicaciones de base Web. La complejidad de muchas de las caracteristicas de nuestro navegador Web y del servidor Web depende del protocolo subyacente, es decir, el Hypertext Transfer Protocol (HTTP). H T T P e n u n protocolo de aplicaci6n (generalmente implementado sobre conexiones TCP/IP). Es u n protocolo sin estado basado en solicitudes y respuestas. Los clientes (como navegadores Web) envian solicitudes a1 servidor (como el servidor Web de una memoria online) para recibir informaci6n (como descargar un catilogo) o para iniciar un procesamiento especifico en el servidor (como realizar una peticidn).

Metodos de solicitud HTTP


Como protocolo de aplicacih, HTTP define 10s tipos de solicitudes que 10s clientes pueden enviar a 10s servidores y 10s tipos de respuestas que 10s servidores pueden enviar a 10s clientes. El protocolo tambikn especifica c6mo estan estructuradas estas solicitudes y respuestas. HTTP/1.0 especifica tres tipos de mktodos de solicitud: GET, POST y HEAD. HTTP/l.l tiene cinco mktodos de solicitud adicionales: OPTIONS, PUT, TRACE, DELETE y CONNECT. De estos, las solicitudes GET y POST cumplen la mayoria de 10s requisitos mis comunes de desarrollo de aplicaciones.

El metodo de solicitud GET


La solicitud GET es el metodo de solicitud mis sencillo y mis frecuentemente utilizado. Se utiliza normalmente para acceder a recursos estiticos como documentos HTML e imigenes. Las solicitudes

lntroduccion a 10s contenedores Web


GET pueden utilizarse para recuperar informaci6n dinimica, incluyendo parimetros de consulta en el URL de solicitud. Por ejemplo, podemos enviar un parimetro nombre, con un valor de Joe, adjuntado a un URL corno http://www.domain.com?nombre=Joe. El senidor Web puede utilizar el valor de este parimetro para enviar contenido especifico a un cliente.

El metodo de solicitud POST


El mktodo de solicitud POST se utiliza comGnmente para acceder a recursos dinimicos. Las solicitudes POST se utilizan habitualrnente para transmitir informacion que depende de la solicitud o cuando una gran cantidad de informaci6n compleja debe ser enviada a1 servidor. La solicitud POST permite la encapsulaci6n de mensajes multiparte en el cuerpo de la solicitud. Por ejemplo, podemos utilizar las solicitudes POST para subir archivos de texto o binarios. De un rnodo similar, podemos utilizar las solicitudes POST en applets para enviar objetos Java serializables o incluso bytes primigenios a1 servidor Web. Las solicitudes POST ofrecen una opci6n mis amplia que las solicitudes GET en tkrminos de contenidos de una solicitud. Existen ciertas diferencias entre las solicitudes GET y POST. Con las solicitudes GET, 10s parimetros de solicitud son transmitidos corno una cadena de consulta adjunta el URL de solicitud. En el caso de las solicitudes POST, 10s parimetros de solicitud son transmitidos en el cuerpo de la solicitud. Esto tiene dos consecuencias. En primer lugar, puesto que la solicitud GET contiene la informaci6n completa de solicitud adjunta el mismo URL ermite a 10s navegadores guardar la direcci6n de la pigina y volver a visitarla mis $ 9 o de la sensibilidad de 10s parirnetros de la solicitud, esto puede ser o no tarde. Dependiendo del t ~ p y deseable. En segundo lugar, algunos servidores pueden irnponer restricciones sobre la longitud del URL de solicitud. Esto limita la cantidad de informaci6n que puede ser adjuntada a1 URL de solicitud. Observe que HTTPll.1 no impone ning6n limite superior en la longitud. Sin embargo, n o podemos garantizar 10s servidores/clientes H T T P se adapten a excesivas longitudes.

El metodo de solicitud HEAD


U n cliente envia una solicitud H E A D cuando s610 desea ver las cabeceras de una respuesta, corno
Contenido-TipooContenido-Longitud.

Las solicitudes de mktodo GET y H E A D no deberian ser programadas para modificar la informaci6n en el servidor. Estas solicitudes pueden ser presentadas multiples veces sin cambiar 10s datos en el servidor y corno tales estin destinadas unicamente a la recuperacidn de informaci6n. Junto con el tip0 de solicitud, la aplicaci6n de cliente tambikn especifica el recurso que necesita corno parte de la cabecera de la solicitud. Por ejemplo, cuando introducimos http://java.sun.com/index.html. En la barra de direccion de nuestro navegador, el navegador envia la solicitud GET a1 senidor Web identificado por j a v a .s u n . com para el recurso i n d e x . html. En el lkxico HTTP, un identificador de recursos uniformes, Uniform Resource Identifier (URI), especifica un recurso. El URI es el URL, excluyendo el nombre del dominio. En nuestro ejemplo, el recurso es el archivo i n d e x . html localizado en el documento raiz del servidor Web que sirve a1 dominio j a v a .s u n . corn

La respuesta HTTP
Cuando un sewidor recibe una solicitud HTTP, responde con el estado de la respuesta y alguna metainformaci6n que describe la respuesta. Todos estos elementos son parte de la cabecera de respuesta. Excepto en el caso de la solicitud HEAD, el servidor tambikn envia el contenido que corresponde a1 recurso especificado en la solicitud. Si un navegador envia una solicitud a http://java.sun.com/index.html, recibe el contenido del archivo i n d e x . html corno parte del mensaje.

Capitulo 5
Los campos de cabecera del contenido de la respuesta contienen informaci6n util que 10s clientes pueden querer comprobar en determinadas circunstancias. Los campos habituales de cabecera incluyen: F e c h a , C o n t e n i d o - T i p o y E x p i r a . Por ejemplo, el campo de c a b e c e r a ~ x p i r de a unapiginapuede ser fijado en la misma fecha que el campo de cabecera F e c h a para indicar que 10s navegadores no deben cachetizar la pigina. Las aplicaciones Web con contenido sensible a1 tiempo pueden necesitar establecer estos campos.
I

Los senidores y clientes que se comunican utilizando HTTP hacen uso de Multi-Purpose Internet Mail Extensions (MIME) para indicar el tip0 de contenido de 10s cuerpos de solicitud y respuesta. Los tipos MIME incluyen t e x t o / h t m l e i m a g e n / g i f . La primera parte de la cabecera indica el tipo de datos (por ejemplo, texto e imagen), mientras que la segunda parte indica la extensibn estindar (como h t m l para texto y g i f para imagen). MIME es una extensi6n de un protocolo de e-mail disefiado para permitir el intercambio de diferentes tipos de archivos de datos. Los senidores H T T P utilizan cabeceras MIME a1 principio de cada transmisi6n y 10s navegadores utilizan esta information para decidir c6mo analizar y generar el contenido. Los navegadores tambiin utilizan cabeceras MIME a1 transmitir datos en el cuerpo de las solicitudes, para describir el tip0 de datos que se envia. Por ejemplo, el tip0 de codificaci6n MIME pordefecto para solicitudes P O S T e s a p p l i cation/x-www- f o r m - u r l e n c o d e d . Las caracteristicas clave de H T T P que es precis0 comprender son:
0

H T T P es un protocolo sin estado muy sencillo y ligero. a1 cliente.

O El cliente siempre inicia la solicitud. El senidor nunca puede realizar una conexi6n de retrollamada

U H'ITP requiere que el cliente establezca conexiones previas a cada solicitud y que el senidor cierre

la conexi6n despues de enviar la respuesta. Esto garantiza que un cliente no puede mantener una conexibn despues de recibir la respuesta. Tanto el cliente como el senidor puede finalizar prematuramente una conexibn. H T T P tenia como objetivo original s e n i r informaci6n estitica, por ello necesitamos considerar ciertos temas adicionales para poder construir aplicaciones dinimicas que comuniquen con clientes utilizando HTTP. En este capitulo, veremos c6mo enfrentarse a algunos de estos temas utilizando contenedores Web J2EE.

Contenedores Web y aplicaciones Web


Las aplicaciones Web son aplicaciones de lado senidor. Los requisitos mis esenciales para el desarrollo de aplicaciones de lado senidor son 10s siguientes:
0 U n modelo d e programaci6n y u n API

U n modelo de programacion para aplicaciones de lado senidor especifica c6mo desarrollar aplicaciones.
0

Soporte de periodo de ejecuci6n de lado servidor Esto incluye apoyo para senicios de red aplicables y periodo de ejecucidn para ejecutar las aplicaciones. Soporte de implementaci6n La implementaci6n es el proceso de instalaci6n de la aplicaci6n en el senidor. Este proceso tambiCn incluye la configuraci6n de 10s componentes de la aplicaci6n, como especificar 10s parimetros de inicializaci6n y especificar cualquier base de datos.

Introduction a 10s contenedores Web


Para cumplir estos requisitos a1 construir y ejecutar aplicaciones Web, la especificaci6n J2EE proporciona 10s elementos siguientes: Servlets Java y Piginas JavaServer Los servletsJava y las PiginasJavaServer (JSP) son 10s bloques de construcci6n para el desarrollode aplicaciones Web en J2EE. En el lixico de J2EK 10s servletsJava y las piginas JSP son conocidos como componentes Web. Aplicaciones Web Una aplicaci6n Web es una colecci6n de servlets Java, piginas JSP, clases ayudantes y librerias de clases, recursos estiticos como documentos HTML, XHTML o XML, e imigenes. U n contenedor Web oara albernar " aolicaciones Web U n contenedor Web es esencialmente un period0 de ejecuci6n Java que proporciona una implementaci6n del API Servlet Java y facilidades para las piginas JSP. El contenedor Web es responsable de inicializar, invocar y gestionar el ciclo de vida de 10s servlets Java y las Piginas JavaServer.
L

Una estructura de empaquetado y descriptores de implementa ci6n La especificaci6n J2EE define una estructura de empaquetado para las aplicaciones Web. La especificaci6n tambiin define un descriptor de implementaci6n para cada aplicaci6n Web. El descriptor de implementaci6n es un archivo HTML que permite la adaptaci6n de aplicaciones Web en el tiempo de despliegue. El siguiente diagrama muestra el contenedor Web de J2EE con dos aplicaciones desplegadas en el mismo --contenedor:

Apl1caa6n .. Web
Servlets Java Sewlets Java
I '

Pag~na JSP

Pagma JSP

Contenedor Web J2EE

En esta seccibn, analizaremos algunos de 10s rasgos bisicos de servlets, piginas JSP y descriptores de implementaci6n. El objetivo de este anilisis es ofrecer una vision completa de lo que supone el desarrollo de aplicaciones Web. En posteriores capitulos, examinaremos el proceso con mas detalle.

Servlets Java
Los servlets Java permiten que la 16gica de aplicacion sea integrada en el proceso de solicitudes y respuestas H T T P y que sea especificada en el API Java Servlet Especificaci6n 2.3 disponible en http://java.sun.com/ productskervletl.

Capitulo 5

Los sewlets Java son programas pequeiios de lado servidor independientes de la plataforma que amplian programdticamente la funcionalidad del sewidor Web. En API Java Sewlet proporciona un marco sencillo para construir aplicaciones en estos sewidores Web.
Para cornprender rnejor la funci6n de la 16gica de aplicacion en el proceso de solicitud-respuesta, considerernos un sewidor de correo de base Web. Cuando nos registrarnos en nuestro sewidor de correo de base Web favorito, el servidor debe poder enviar una pigina con vinculos a nuestro correo, nuestras carpetas de correo, nuestro libro de direcciones, etc. Esta informaci6n es dinirnica, en el sentido en que cada usuario espera ver su buz6n individual. Para generar este contenido, el sewidor debe ejecutar una 16gica de aplicaci6n cornpleja para recuperar el correo y cornponer una pigina. Los clientes pueden enviar information de context0 o especifica del cliente a1 sewidor en las solicitudes pero, ic6rno puede el sewidor decidir c6mo debe ser generado el contenido? H T T P no define un rnedio estindar para integrar la bgica de aplicaci6n durante la fase de generaci6n de respuestas. N o existe un modelo de prograrnaci6n especificado para estas tareas. HTTP define c6rno pueden 10s clientes solicitar inforrnaci6n y c6rno pueden responder 10s sewidores per0 no intewiene en cBrno puede ser generada la respuesta. Aqui es donde se hacen evidentes 10s beneficios de tecnologias de lado servidor tales corno 10s servlets Java y las piginas JavaServer. C o n estas tecnologias, podernos integrar la 16gica de la aplicaci6n de adaptaci6n durante el procesarniento de respuestas y las etapas de generaci6n de respuestas. Los sewlets Java no son aplicaciones invocadas por usuarios. En su lugar, el contenedor Web en el que se despliega la aplicaci6n Web que contiene 10s sewlets invoca 10s sewlets basindose en solicitudes entrantes HTTP. Cuando un sewlet ha sido invocado, el contenedor Web envia la inforrnaci6n de la solicitud entrante a1 sewlet, de mod0 que el sewlet pueda procesarla y generar una respuesta dinirnica. El contenedor Web actua corno interfaz con el servidor Web aceptando solicitudes para sewlets y transrnitiendo respuestas de vuelta a1 sewidor Web. En cornparaci6n con C G I y extensiones de sewidor de propiedad corno NSAPI o ISAPI, el rnarco de servlet proporciona una rnejor abstracci6n del paradigma de solicitud y respuesta H I T P especificando un API de prograrnaci6n para encapsular solicitudes y respuestas. Adernis, 10s servlets tienen todas las ventajas del lenguaje de prograrnaci6n Java, incluyendo la independencia de la plataforma. Las aplicaciones basadas en sewlets Java pueden ser desplegadas en cualquier sewidor Web con contenedores Web incorporados (dentro del proceso) o basados en conectores (fuera del proceso), con independencia del sisterna operativo y de la plataforrna de hardware.

k Para entender c6rno un servlet interact6a con un sewidor Web a travks de un contenedor Web.
considerernos el proceso bisico de invocaci6n con que el sewidor Web esti recibiendo una solicitud HTTP. Corno hernos visto antes, el protocolo H T T P esti basado en un rnodelo de solicitudes y respuestas. U n cliente conecta con un sewidor Web y envia una solicitud H T T P en la conexi6n. Basado en un URL de solicitud, la siguiente secuencia de eventos tiene lugar en una secuencia tipica (las flechas hacia la derecha indican solicitudes y las flechas hacia la izquierda indican respuestas):

lntroduccion a 10s contenedores Web


/

Aphcac16n Web

I
Uno o mas

1 bvegador I Web i

1--

Solicitud

/'

sewlets o
JSP

Respuesta

El semidor Web tiene que descifrar si la solicitud entrante corresponde a una aplicaci6n Web en el contenedor Web. Esto requiere un entendimiento implicit0 entre el semidor Web y el contenedor Web. Los contenedores Web utilizan la nocidn de contexto de servlet para identificar las aplicaciones Web. Este contexto puede ser especificado cuando la aplicaci6n es desplegada sobre el contenedor. Si el contenedor Web puede manejar la solicitud, el semidor Web la delega en 61. Podemos pensar en este proceso como el semidor Web invocando un mktodo en el contenedor Web, pasindolo a la informaci6n de la solicitud. Una vez que el contenedor Web ha recibido la solicitud, decide qu6 aplicaci6n debe manejarla. En una aplicaci6n Web de JZEE, una solicitud H T T P puede ser representada en un semlet, una pigina JSP o cualquier recurso estitico. Esta representacidn esti basada en patrones URL. Los recursos estiticos incluyen piginas HTML/XML, imigenes y archivos de clase applet. Todos estos recursos son parte de la aplicaci6n Web. Cuando empaquetamos y desplegamos una aplicaci6n Web, especificamos esta informaci6n de representacidn. El contenedor Web utiliza esta informaci6n de representaci6n para representar cada solicitud entrante en un semlet, pigina JSP o recurso estitico. Si el recurso es representado en un recurso estitico, el contenedor Web simplemente pasa el recurso tal y como esti a1 semidor Web. Esto conforma el cuerpo de la respuesta que el semidor Web envia a1 navegador. Basindose en la informaci6n de representaci6n, el contenedor Web determina si la solicitud debe ser manejada por un semlet. Si la solicitud debe ser manejada por un semlet, el contenedor crea o localiza una instancia de semlet y delega la solicitud. En prdximos capitulos, veremos cdmo el contenedor Web lleva a cab0 este proceso y quk factores lo gobiernan. solicitud H T T P y la respuesta H T T P en la instancia semlet. Para el servlet, estos objetos representan las corrientes de solicitud y respuesta del navegador. El semlet puede leer la informaci6n de la solicitud y escribir una respuesta para estas corrientes. Para escribir una respuesta, el semlet puede utilizar 10s mktodos print1 ( ) del objeto asociado j ava .i o .Printwriter. Esto es equivalente a escribir contenido en la conexi6n ya abierta desde el navegador Web.

0 Cuando el contenedor delega la solicitud en un semlet, tambikn pasa objetos que encapsulan la

Hay dos pasos necesarios para construir y desplegar una aplicaci6n basada en un semlet:
0

Escribir 10s semlets con la lbgica de aplicaci6n requerida. ~ s t es a la fase de despliegue.

Capitulo 5
0 Proporcionar un context0 y la informaci6n opcional de representaci6n de patr6n URL durante la fase de despliegue. Esta informaci6n de representaci6n es utilizada para identificar el servlet apropiado para manejar una solicitud.

Paginas JavaServer
La generacion de contenido dinimico puede conseguirse mediante generaci6n de contenido programitico o generacion de contenido basado en una plantilla. Los servlets Java estin dentro de la primera categoria y las piginas JavaServer USP) pertenecen a la segunda. Las piginas JSP estin especificadas en la especificaci6n 1.2 de JavaServer Pages, disponible en http://java.sun.com/products/jsp/ Las paginas JavaServer son una extension de la tecnologia de servlets Java. Sin embargo, en contraste con 10s servlets, que son puros programas Java, las piginas JSP son documentos de base textual. Una pigina JSP contiene dos partes:
0 HTML o XML para el contenido estitico

O Etiquetas y scriptlets JSP escritos en Java para encapsular la 16gica que genera el contenido dinimico
Puesto que una pigina JSP proporciona una representaci6n general de contenido que puede producir mdltiples vistas dependiendo del resultado de las etiquetas y scriptlets JSP, una pigina JSP actda como una plantilla para producir contenido. Una plantilla es una pigina de anotaci6n (como HTML) con guardasitios especiales (etiquetas y scriptlets JSP) integrados. Estos guardasitios contienen informaci6n de procesamiento para el procesador de plantilla (o generador de contenido). En una pigina JSP, la anotacibn usual nos permite definir la estructura estitica y el contenido de una pigina. Las etiquetas y scriptlets adicionales integrados en la pigina nos permiten incluir bgica de programacidn para ser ejecutada durante la generacidn de piginas. La ventaja clave de esta tecnologia es que ayuda a mantener el diseiio del contenido y las actividades de desarrollo en combinaci6n libre con el diseiio y desarrollo de la 16gica de aplicacidn. Si desarrollamos el contenido Gnicamente con servlets, las dos actividades estarin estrechamente entrelazadas. Esto no es deseable porque estas aplicaciones son mis dificiles de mantener. En algunas tecnologias controladas por plantilla como Active Server Pages (ASP), las plantillas son evaluadas en el periodo de ejecucidn. Es decir, el procesador de plantilla convierte dinimicamente las etiquetas especiales en contenido normal. Este es un proceso de periodo de ejecuci6n y cada vez que se solicita una pigina, el procesador de plantilla interpreta la plantilla una y otra vez. A diferencia de ASP, la tecnologia JSP esti basada en la compilacidn de piginas. En lugar de interpretar las piginas JSP, el contendor Web la convierte en una clase de servlet y la compila. Este proceso ocurre habitualmente cuando el contenedor Web invoca una pigina JSP por primera vez en respuesta a una solicitud o en el arranque del contenedor. Los contenedores Web tambikn nos permiten precompilar piginas JSP en servlets. La mayoria de 10s contenedores disponibles en la actualidad repiten este proceso siempre que se modifica la pigina JSP. Esto se denomina fase de traduccidn,de pigina. El.contenedor invoca el servlet generado/compilado para solicitudes posteriores a IaJSP. Esta es la fase de procesamiento de solicitud. En la figura siguiente se muestran las diferentes fases (la flecha blanca representa el proceso de compilaci6n de pigina):

Introduccion a 10s contenedores Web


wins
JSP

Fasede traduccion de pAgina: p6gina Solicitud


-

m
-

compilada en un sewlet

Navegador webp 4

Respuesta

m
Java

Fase de procesamiento

I desewlet

desolicitud:invocation

Una vez compilada la pigina JSP en un servlet, el resto del procesamiento de la solicitud y la generaci6n de respuesta es igual a1 proceso descrito previamente en el caso de 10s servlets. Esta arquitectura nos lleva a aplicaciones muy utiles y flexibles utilizando piginas JSP y servlets:

a
0

Podemos utilizar s61o servlets para 16gica de aplicaci6n y generaci6n de contenido Podemos utilizar tambikn piginas JSP para 16gica de aplicaciones y generaci6n de contenido Podemos combinar las anteriores con la 16gica de aplicaci6n manejada por servlets y generaci6n de contenido manejada por piginas JSP

Descriptores de despliegue
Los descriptores de despliegue son una parte integrante de las aplicaciones Web J2EE. Ayudan a gestionar la configuraci6n de las aplicaciones Web una vez desplegadas. Para 10s contenedores Web, el descriptor de despliegue es un archivo XML llamado w e b . x m l almacenado en el directorio /WEB- INF de la aplicaci6n Web. La especificacidn deJava Servlets proporciona una definici6n de tip0 de documento (DTD) para el descriptor de despliegue. Este esti disponible en http:lljava.sun.cornldtdMleb-app-2-3.dtd. U n descriptor de despliegue tiene varios prop6sitos:

Inicializaci6n de pardmetros para servlets y aplicaciones Web Esto nos permite minimizar el nivel de inmodificabilidad de 10s valores de inicializaci6n en nuestras aplicaciones Web. Por ejemplo, si nuestro servlet requiere acceso a una base de datos, el mejor lugar para especificar 10s detalles, como el registro y la contraseiia, es el descriptor de despliegue. Esto nos permite configurar nuestra aplicaci6n sin tener que recompilar 10s servlets. Definiciones de servlet/JSP Cada servlet o pigina JSP precompilada utilizada en nuestra aplicaci6n Web debe estar definida en el descriptor de despliegue. Esta entrada incluye el nombre del servlet o JSP, la clase del servlet o JSP, y una descripci6n optional. Representaciones de servlet/JSP Los contenedores Web utilizan esta informaci6n para representar solicitudes entrantes a servlets y piginas JSP. Conoceri mis detalles sobre estas representaciones en el capitulo 9. Tipos MIME Puesto que cada aplicaci6n Web puede contener varios tipos de contenido, podemos especificar 10s tipos MIME para cada tip0 en el descriptor de despliegue.

Capitulo 5

Seguridad Podemos conseguir el control de acceso para nuestra aplicacion utilizando el descriptor de despliegue. Por ejemplo, podemos especificar si nuestra aplicacidn Web requiere un registro y, si es asi, cdmo deberia ser esa pigina de registro y quk funcidn debe tener el usuario.

El descriptor de despliegue puede tambikn puede ser utilizado para adaptar otros elementos incluido las piginas bienvenida, piginas de error y configuracidn de sesion. Aprenderemos mis sobre estos temas en el capitulo 9.

Estructura de aplicaciones Web


Una aplicacion Web consta de cuatro partes:

O Un directorio p6blico
O Un archivoWEB- INF/Web xml

El irea pliblica es la raiz de la aplicaci6n, excluyendo el directorio WEB- IN??. Si esti familiarizado con servidores Web como Apache, kste es equivalente a1 directorio h t d o c s donde tendriamos todos nuestros archivos HTML. El contenedor Web puede servir a cualquiera de 10s archivos del irea pGblica. El directorio WEB- I N F es un irea privada y el contenedor no serviri contenidos de este directorio a 10s usuarios. Los archivos de kste estin destinados Gnicamente a1 uso del contenedor. WEB- INF contiene, entre otras cosas, el descriptor de despliegue, un directorio c l a s s e s y un directorio l i b . El directorio c l a s s e s es utilizado para almacenar servlets compilados y otras clases de utilidad. Si una aplicacidn ha empaquetado archivos JAR (por ejemplo, un API tercero empaquetado como un archivo JAR), pueden ser copiados en el directorio l i b . El contenedor Web utiliza estos dos directorios para ubicar servlets y otras clases dependientes.

Tipos de contenedores Web


Existen fundamentalmente tres formas de configurar contenedores Web. Recordemos del Capitulol que un contenedor Web bien implementa 10s servicios HTTP subyacentes o delega estos servicios a servidores Web externos:
0

Contenedor Web en u n senidor de aplicacion JZEE La mayoria de 10s servidores comerciales de aplicaciones JZEE, como WebLogic, Inprise Application Server, iPlanet Application Server, Websphere Application Server incluyen en la actualidad contenedores Web integrados. Contenedores Web integrados en servidores Web Este es el caso de 10s servidores Web Java puro que contienen contenedores Web integrados. Jakarta Tomcat (en http://jakarta.apache.org), que es la implernentacion de referencia del contenedor Web, tambien esti dentro de esta categoria. Tomcat incluye un servidor Web junto con un contenedor Web. Contenedor Web en un periodo de ejecuci6n independiente En el universo exterior a JZEE, kste es el escenario mis comlin. Los servidores Web como Apache o Microsoft IIS requieren un periodo de ejecucion distinto Java para ejecutar servlets y un plug-in

lntroduccion a 10s contenedores Web


de servidor Web para integrar el period0 de ejecucion con el servidor Web. Los sisternas de procesarniento de servlet/JSP cornercialrnente disponibles corno JRun de Allaire y ServletExec de New Atlanta (ahora parte de la farnilia de productos Unify's eWave) ofrecen plug-ins para integrarlos con 10s servidores Web. La elecci6n de un tipo de contenedor depende por cornpleto de 10s requisitos de nuestra aplicaci6n:Por ejernplo, si s610 estuvi6rarnos interesados en construir una nueva aplicaci6n Web de base Java, elegiriarnos la segunda o la tercera configuraci6n. Sin embargo, con la unificacidn de las norrnas de procesarniento Web y de ernpresa rnediante J2EE, la prirnera configuration se esti convirtiendo cada vez en la rnis cornun.

Una sencilla aplicacion Web


Ahora que hernos visto una arnplia description de la arquitectura de contenedores Web de J2EE y de aplicaciones Web, construyarnos una aplicacion Web de rnodo que podarnos hacer un recorrido por 10s aspectos bisicos del desarrollo de aplicaciones Web con J2EE. Nuestra aplicacion Web hari dos cosas:
0

Sugerir al usuario un nornbre una direcci6n de e-mail

o Irnprirnir un saludo basado en la hora del dia


Aunque existen diferentes cornbinaciones de servlets y piginas JSP que podrian utilizarse para desarrollar esta aplicaci6n, utilizarernos la siguiente:
0 0

Una pigina H T M L con un forrnulario para recabar el nornbre y la direction de e-mail del usuario U n servlet para procesar la solicitud y generar HTML para rnostrar el rnensaje de bienvenida

o U n descriptor de despliegue
Una vez hayarnos cornpletado este ejercicio, cornprobari lo sencillo e intuitivo que es el proceso de construcci6n de una aplicaci6n Web.

Prepara el contenedor Web


Para construir, desplegar y ejecutar nuestra aplicaci6n Web necesitarnos un contenedor Web (anteriorrnente conocido corno motor de servlet/JSP) que curnpla con la especificaci6n Java Servlet 2.3. hay diferentes productos cornerciales disponibles en el rnercado pero en 6ste y en 10s siguientes capitulos recornendarnos que utilice la irnplernentaci6n de referencia J2EE de http://java.sun.corn.

Crear el archivo HTML


Cree un archivo HTML con el siguiente contenido y guirdelo corno %BOOK-HOME%\ChOS\greeting\index.html.

Capitulo 5
<body> <hl>Welcome</hl> <form a c t i o r 1 = " / g r e e t i n g / s e r v l e t / G r e e t i r ~ g S e r v 1 e t " rnethod="POST"> <p>Your Name <input type="textq' size="4 0" name="name" /></p> <p>Your Email <input type="textW size="40n name="emailn / > <input type="submit" VALUE="Submit" /></p> </form> </body> </html >

Observe el contenido de la etiqueta <form>. Esta etiqueta tiene una solicitud POST para un formulario que recoge 10s valores para 10s parlmetros nombre y email.

Crear un servlet
El siguiente paso es crear un servlet. Este servlet procesa la solicitud HTTP POST presentada desde index.html. Cree una clase Java llamada Greet ingservlet y guirdela como %BOOK-HOME%\ChO5\greeting\GreetingServlet.]ava.

No es necesario que nos preocupemos por poner nuestro servlet en el directorio classes en esta fase porque la herramienta que utilizaremos para construir nuestra aplicacidn W e b realizara' este proceso por nosotros.
import. import import import import import import import public
javax.servlet.http.HttpServ1et; javax.servlet.http.HttpServ1etRequest; javax.servlet.http.HttpServletRespor1se; javax.servlet.ServletException;

j a v a . io. I O E x c e p t i o n ; java.io.PrintWriter; java.uti1 .Calendar; j ava.uti1 .GregorianCalendar; class GreetingServlet extends HttpServlet

protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.qetParameter ("r~ame"); String email = request.getParameter("emaill'); String message = null; GregorianCalendar calendar = n e w GregorianCalendar(); if (calendar.get (Calendar.AM PM) == Calendar.AM) [ message = "Good Morning"; I else { messaqe = "Good Afternoon";

I
response.setContentType ("text/htmll') ; Printwriter out = response.getWriter ( ) out .println ("<html>") ; out .println("<body>"); out.prir~tln("<p>" + message out.println("<p>
")

+ ", " +

name

"</p>");
("

Thanks for registering your email with us.</p>"); out.println("<p> - The Pro Java Team. </p>");

+ email

Introduccion a 10s contenedores Web

Para poder compilar el servlet, debe tener j 2 e e . j a r (que se encuentra en B JZEE-HOME",lib\) en su CLASSPATH. Ejecute el siguiente comando d e s d e % ~ 0 0 ~ ~ ~ 0 ~ ~ % \ ~ h 0 5 \ ~ r e e t i n ~ \ ~ a r a c o m servlet:
javac

-classpath

% 3 2 E E d H O M E % \ l i b \ j 2 e e . jar;.

GreetingServet. java

Construir la aplicacion Web


En este punto, debe tener 10s siguientes archivos:

Los componentes Web en J2EE estin empaquetados en un archivo WAR, Web Application Archive, que es un JAR similar al paquete utilizado para las librerias de clase Java. Es posible crear archivos WAR manualmente, sin embargo utilizaremos la herramienta d e p l o y t o o l que estl incorporada c o m o parte de la Implementacibn de Referencia J2EE. Utilizaremos esta herramienta para crear aplicaciones en pr6ximos capitulos y Cste es un buen momento para aprender algunas de sus caracteristicas bisicas. Arranque la herramienta de implenientaci6n de J2EE ejecutando el archivo d e p l o y t o o l . b a t en el Application o directorio 't J2EE-HOME: \ b i n . Cree una nueva aplicacibn utilizando el b o t 6 n ~ e w seleccionando New 1 A p p l i c a t i o n del mend F i l e . Nombre a la a p l i c a c i b n ~ r e e t i n g :

Applicatmn DisplayNmne:

1 Greet~ng

Nuestra aplicacibn seri parte de esta aplicacibn Enterprise. Seleccione la aplicacibn ~ r e ei n t g en el arb01 de la izquierda y aiiada un nuevoWeb Component utilizando el mend F i l e (Archivo). Salte la primera pantalla de ~ e Component w W i z a r d ( A s i s t e n t e p a r a n u e v o c o m p o n e n t e ) hasta que llegue a la p a n t a h WAR F i 1e:

Capitulo 5

~wnRfile IS requlred to contains this web component You can create r new waRfllsrn~hin an ensltng apubcation or use an exisbng WAR file Meryou have selected a WAR nle. add the web componenlflles and any other deslred files to rts contents OphOnally,p u tan also pmnde a descrlpllon,denne me advanced semngs, and choose Icons for me WWl Ills
WAR Flle Locdlml'

Cteale new WIRIUr in AwllcaMn

--

eeet~na
WAR Dnplw Name

7-I

Pulseel b o t 6 n ~ d i (Editar) t y a f i a d a ~ r e e t i n g ~ e r v l e t . c l ay si sn d e x . h t n l a 1 componente Web:

lntroduccion a 10s contenedores Web


Avance hasta la siguiente pantalla del asistente y seleccione desplegar un solo servlet:

Vaya a la siguiente pantalla. Nombre al servlet greeting y elija el archivo de clase GreetingServlet:

Please choose heJSP rile orteM0tcrass and pravlda aname for d OpUOnBIb, wu can define the relathe poslhon In wnirh I h l s componenlrlll be loadedwhen me rmb applicahon Is statled YOU (an also provide a dsstn~~tJOn and Icons forme component

b a d a any timd
1 -

. -

1 1 1
I

Capitulo 5
Esto es t o d o lo que necesitamos para establecer el asistente. Puede pulsar el b o t h Finish (Finalizar) ahora o seguir hasta el final del asistente para ver el descriptor de despliegue:

The hllwrnD deployment descrtplorwll be generaled for your WF8 110 TO change am( oltne senhgs, cllck Back tlmu are salisned wlM the settings. d~ckflnish .-

Una vez haya salido del asistente, veri el componente Web reciin creado en la ventana principal:

Introduccion a 10s contenedores Web


Esto completa la creaci6n de nuestra primera aplicaci6n Web.

Desplegar la aplicacion Web


El siguiente paso es desplegar nuestra aplicaci6n W e b reciin creada sobre un servidor de rnodo que 10s navegadores clientes puedan acceder a ella. Si la iniplementacion de referencia J2EE el servidor n o e s t i siendo ejecutada, necesita comenzar ejecutando j 2 e e - v e r b o s e desde dentro de't J2EE-HOME: \ b i n . Conecte entonces la herramienta de despliegue a1 servidor que e s t i siendo ejecutndo, s e l e c c i o n a n d o ~ d dS e r v e r del menil F i l e (Archivo) y atiadiendo un servidor llamado L o c a l h o s t :

Ahora podemos desplegar el componente Web. Selection D e p l o y (Desplegar) del menu T o o l s (Herramientas) para iniciar el asistente de despliegue:

The aemr can send back a tliemt JAR Ne. It contains the extra RMIllIOP stub classes ihai client appllcatnns written to access ChLs

Asegurese de q u e c r e e t i n g e s t i seleccionado mientras el objeto es desplegado y p u l s e N e x t (Siguiente):

281

Fije C o n t e x t Root e n g r e e t i n g ; asi se configura el URLpara acceder a la aplicaci6n. S e l e c c i o n e ~ e xy t despues F i n i s h para iniciar el proceso de despliegue:

Veb Componenls Deployed. )eploymenl of Oreeting is complete.

Introduccion a 10s contenedores Web


Ahora estamos preparados para probar nuestra aplicaci6n.

Ejecutar la aplicacion Web


El sewidor ya debe estar ejecuthndose; abra su navegador y vaya a http://localhost8000/greeting/ index.htrnl, donde debe ver algo asi:

Introduzca su nombre y direcci6n de e-mail, y haga clic en Submit. Su navegador debe mostrar la sieuiente bienvenida del e a u ' i ~ o he P r o J a v a Server. El verdadero mensaie de bienvenida depende " del momento del dia en que ejecute esta aplicaci6n:

Good Afternoon, Subrahmanyam AUamaraju

Thanks for registering your email (subrah@ubrahmanyam corn) w& us


-

The Pro Java Team

La siguiente fase es comprender c6mo funciona esta aplicaci6n.

Como funciona la aplicacion


La figura que aparece a continuaci6n muestra lo que ocurre entre el navegador Web y la aplicaci6n Web. Las flechas numeradas indican la secuencia en la que solicitudes y respuestas son procesadas:

283

Capitulo 5

Apl~cac~on Web de b~enven~da

Navegado Web (con sewlclo H T P )


4

En respuesta a la primera solicitud que el navegador realiza a1 sewidor (http://localhost:80OO/greeting/ index.htrnl), el contenedor Web s i n e el index.htm1 bajo \greeting\index.htrnl. En la actual configuracidn, la ruta URL g r e e t i n g representa una aplicacidn Web situada en \ w e b a p p s \ g r e e t i n g . En general, 10s sewidores y contenedores Web consideran i n d e x . h t m l corno el archivo de bienvenida por defect0 en cualquier directorio en la ruta URL. Las flechas nurneradas (I), (2) y (3) rnuestran esta secuencia. La segunda solicitud (http:Nlocalhost:808O/~eeting/servlet/Greetinelet) realizada el contenedor Web es la solicitud POST HTTP con 10s parirnetros nornbre y ernail. Basindose en la ruta g r e e t i n g / s e r v l e t y la definicidn del sewlet del descriptor de despliegue, el contenedorweb delega esta solicitud en G r e e t i n g s e r v l e t . (Examinaremos el descriptor de despliegue rnuy pronto.) El sewlet realiza entonces las siguientes tareas:
0

Extrae 10s parimetros de solicitud: Esto conlleva extraer 10s parimetros "nornbre" y " e m a i l " de lasolicitud

0 Ejecuta la logica de aplicacidn: En nuestro ejemplo, esto supone generar un mensaje de bienvenida 0

Genera la respuesta: DespuCs de procesar la solicitud, el sewlet genera un docurnento HTML con el rnensaje de bienvenida

El navegador recibe la respuesta asi generada por el sewlet. Esta secuencia aparece representada por las flechas nurneradas (4), (5), (6) y (7). Brevernente, asi es corno los contenedores Web delegan solicitudes en 10s servlet en las aplicaciones Web. Aprenderemos mis detalles sobre este proceso en 10s capitulo 6 y 7.

El servlet Greeting
N o se preocupe por cornprender cada linea de c6digo en ~ r e e t i n g s e r v l e tj a v a . Nuestro objetivo es sirnplernente obtener una vision general de las funciones de un sewlet.

lmportar 10s paquetes de sewlet


El API JavaSewlet consiste en dos paquetes: j a v a x . s e r v l e t , y j a v a x . s e r v l e t h t t p . Observe que todos 10s paquetes j a v a x son parte de Java 2 SDK, Enterprise Edition.

lntroduccion a 10s contenedores Web


D e estos dos paquetes, el paquete j a v a x .s e r v l e t contiene clases e interfaces de servlet que son independientes de HTTP. El resto de las clases que son especificas para HTTP forrnan parte del paquete
j avax. servlet .http.

Adernis de 10s dos anteriores, la clase G r e e t i n g s e r v l e t tarnbien necesita importar clases de 10s paquetes j ava. i o y j ava. util:
import import import import import import import import javax.servlet.ServletException; javax.servlet.http.HttpServ1et; javax.servlet.http.HttpServ1etRequest; javax.servlet.http.HttpServ1etResponse; java.io.IOException; j ava. io. Printwriter; java.util.Calendar; j ava. util .GregorianCaler~dar;

Declaraci6n de clase Todos 10s servlets son necesarios para implementar la interfaz j avax .servlet .servlet. Sin embargo, para 10s servlets en aplicaciones Web, la clase j avax .servlet .http .Ht tpServlet proporcionauna implementaci6n de esta interfaz. Por lo tanto, la clase GreetingServlet ampha la clase HttpServlet:
public class GreetingServlet extends HttpServlet
{

Revisar la solicitud POST HTTP En el servlet GreetingServlet, el metodo d o p o s t ( ) rnaneja la solicitud POST HTTP. Este metodo toma un objeto H t t p S e r v l e t R e q u e s t que encapsula la informaci6n contenida en la solicitud y un o b j e t o ~ t t p ~ e r v l e t R e s p o nque s e encapsulalarespuestaHTTP. Nuestra implementaci6n del metodo d o ~ o t s ( ) incluye dos tareas: extraer 10s parimetros FORM de la solicitud HTTP y generar la respuesta. Extraer parametrosde HttpSewletRequest Podernos u t i h a r el metodo g e t p a r a m e t e r parimetros de la solicitud HTTP:
String name String email
=

()

de la i n t e r f a z ~ t t ~ ~ e r v l e t ~ epara ~ u extraer est

r e q u e s t . g e t p a r a m e t e r ( " n a m e " ); r e q u e s t . g e t p a r a m e t e r ( '' e m a i l " ) ;

La primera llamada extrae el parirnetro llamado n a m e en la etiqueta <FORM> del archivo index. h t m l
Aqui tiene un resumen:
<p>Your Name <input type="textM size="4OW name="nameV></p>

El metodo ge t p a r a m e t e r ( ) exarnina todos 10s parimetros disponibles en la solicitud y extrae un parirnetro llamado name. De un mod0 similar, podemos extraer el parimetro email. Observe que estos parimetros no necesitan ser extraidos en ningtin orden determinado. Por ejemplo, podemos extraer primer0 el parirnetro e m a i l y despuks extraer el parimetro name. Asi terrnina la parte de procesamiento de solicitudes. El siguiente paso es preparar la respuesta. Generar respuesta El siguiente paso es preparar el contenido dinimico que debe ser enviado a1 usuario. En la respuesta, nos interesa mostrar un mensaje de bienvenida, como el siguiente:

Capitulo 5
Good Afternoon, Subrahmanyam Allamaraju Thanks for registering your email (subrah@subrahmanyam.com)with us.
- The Pro Java Team.

En este ejernplo, el servlet utiliza la corriente de respuesta asociada a1 objeto respuesta para irnprirnir directarnente el contenido. Observe que las piginas JSP ofrecen una rnejor alternativa para la generaci6n de contenido dinarnico. Sin embargo, para mayor sirnplicidad, utilizarernos 10s servlets en su lugar. El siguiente fragment0 de c6digo calcula un rnensaje de bienvenida dependiendo del rnornento del dia en que se ernita. Observe que Csta es la 6nica 16gica de aplicaci6n ejecutada en esta aplicaci6n. Corno verernos en 10s Capitulos 7 y 8, podernos aplicar una 16gica de aplicaci6n rnis cornpleja (corno el acceso a una base de datos) en este punto:
S t r i n g message = n u l l ; G r e g o r i a n C a l e n d a r c a l e n d a r = new G r e g o r i a n C a l e n d a r ( ) ; i f ( c a l e n d a r . g e t (Caler1dar.AM-PM) == C a l e n d a r . A M ) { m e s s a g e = "Good M o r n i n g " ; ] else { m e s s a g e = "Good A f t e r n o o n " ;

I
Observe que Csta es una forrna algo tosca para un rnensaje de bienvenida. El servlet utiliza un objeto j a v a .u t il .G r e g o r i a n c a l e n d a r para saber si el rnornento del dia corresponde a AM o PM, y consecuenternente, prepara la respuesta con una cadena de rnensaje. DespuCs de procesar este rnensaje, el servlet esti preparado para generar la respuesta. Este proceso conlleva 10s siguientes pasos:
O

Establecer un tipo de contenido (MIME) para la respuesta; en nuestro ejemplo es t e x t / h t m l :

Obtenerunobjeto j a v a . i o . P r i n t w r i t e r delobjetorespuesta:
Printwriter out
=

r e s p o n s e . g e t W r i t e r ( 1;

Irnprirnir la respuesta utilizando el objeto P r i n t w r i t e r :


out . p r i n t l n ("<html>"); o u t . p r i n t l n ("<body>") ; o u t . p r i n t l r ~ ( " < p > "t m e s s a g e

",

"

name

"</p>"); email
("

o u t . p r i n t l n ( " < p > Thanks f o r r e g i s t e r i n g " ) with us.</p>") ; o u t . p r i n t l n ( " < p > - The P r o J a v a o u t . p r i n t l n ("</body>") ; out . ~ ~ r i r ~ t l r ~ ( " < / h t m ;l > " ) Team.

your

email

</p>");

o Cerrando el objeto p r i n t w r i t e r :
out. close ( ) ;

Estos pasos dan corno resultado el docurnento HTML que aparece en el navegador en respuesta a la solicitudPOST.

lntroduccion a 10s contenedores Web


El descriptor de despliegue
En nuestra aplicaci6n de ejem~lo, el archivo de descriptor de despliegue (web.xml) es creado para nosotros pordeploytool. Si b u s c a ~ n % ~ 2 ~ ~ ~ ~ 0 ~ ~ % \ p u b l i c ~ h t m l \ g r e e t i n g \ , e n c o n t r a r d u n a r c h i v o llamado original .war. Este es el archivo WARpara nuestra aplicaci6n Web greeting y, como un WAR es un JAR, podemos examinar 10s contenidos de original.w a r utilizando la herramienta estdndar j ar. Una herramienta zip, como WinZip, tambien es capaz de entender archivos WAR. Si utiliza una de estas herramientas para examinar original .war,encontrari la siguiente estructura:
\greeting \ i n d e x . html \WEB-INF \Web. xml \classes \GreetingServlet. class

Obsewe que la herramienta de despliegue ha situado nuestro sewlet en el directorio correcto. Esto pone de manijiesto una de las ventajas de utilizar esta herramienta para near aplicaciones, en lugar de crearla de forma manual.

Puede abrir entonces Web. xml y examinar su contenido. Recuerde que este archivo incluye la informaci6n de configuraci6n para nuestra aplicaci6n Web. La primera linea del descriptor de despliegue es una declaraci6n XML especificando la versi6n de XML y la codificaci6n utilizada:

Esto va seguido por la declaraci6n del tip0 de documento especificando el URL para el D T D utilizado para esta aplicaci6n:
< ! DOCTYPE Web-app

PUBLIC

'-//Sun

M i c r o s y s t e m s , I n c . //DTD Web A p p l i c a t i o n 2.3//EN1 ' h t t p : / / j a v a . sun. ~orn/dtd/Web-app~2~3.dtd'>

En el caso de las aplicaciones Web, el D T D es parte de la especificaci6n J2EE para aplicaciones Web y es estdndar para todas nuestras aplicaciones Web. La verdadera definici6n de 10s sewlets aparece entre etiquetas <Web-app>. Dentro de la etiqueta <servlet>, fijese en las tres entradas para el nombre del sewlet, el nombre de presentacih del sewlet, y la clase cualificada Java. La etiqueta <servle t> permite a1 contenedor Web conocer el nombre utilizado para referirse a un sewlet:

Recuerde que FORM en index.htm1 envia la solicitud a un URL relativo, /greeting/servlet / GreetingServlet. El valor de <servlet-name> es un alias para el verdadero nombre de clase. Este rasgo nos permite cambiar 10s archivos de clase sewlet cambiando nuestras piginas HTML u otros sewlets. Tambiin podemos desplegar el mismo sewlet mis de una vez en la misma aplicaci6n Web. Para conseguirlo, s61o necesitamos utilizar nombres diferentes.

Capitulo 5

Este capitulo ofrece un anilisis de 10s contenedores Web, sin entrar en muchos detalles sobre 10s API subyacentes. El prop6sito de este capitulo es introducirle en el desarrollo de aplicaciones Web utilizando servlets Java. Ademis de ilustrar el modelo de programaci6n de servlets Java con la ayuda de una sencilla aplicaci6n, este capitulo cubre 10s siguientes puntos:
0 0
0

Los principios bisicos de HTTP: 10s diferentes tipos de solicitudes y detalles del paradigma de solicitudes y respuestas H T T P Los servlets Java, las paginas JSP y 10s descriptores de despliegue Los pasos necesarios para la construcci6n de una sencilla aplicacion Web para recabar datos de 10s usuarios y generar una respuesta utilizando la implementaci6n de referencia J2EE

Aunque estas ireas ilustran el modelo bisico de desarrollo de aplicaciones, hay otras diversas caracteristicas necesarias para construir utiles aplicaciones Web de calidad de producci6n. En 10s siguientes capitulos profundizaremos en las tecnologias de servlets y JSP. Mis concretamente, en 10s siguientes cuatro capitulos trataremos:
0 0

En el capitulo 6, examinaremos el API Servlet con detalle. Ademis, este capitulo tambitn analizari el ciclo de vida de 10s servlets y el API de solicitud y respuesta. El capitulo 7 le presentari 10s conceptos de sesiones y contexto, y su funci6n esencial para el desarrollo de aplicaciones Web. Este capitulo tambitn estudiari c6mo utilizar dos o mis servlets o piginas JSP en coordinacion. El capitulo 8 le presentari 10s filtros. Los filtros le permiten intenenir en el proceso en el que el contenedor invoca 10s senlets y las piginas JSP, o sirve contenido estatico. El capitulo 9 analizari detenidamente 10s descriptores de despliegue y c6mo utilizarlos para proporcionar seguridad a las aplicaciones.

Estos capitulos le mostrarin el desarrollo de varias aplicaciones Web. Estas muestras se centrarin en diferentes aspectos del API servlet e incorporarin lo que ha aprendido en este capitulo.

Programacion de servlets
Los servlets son bloques de construccidn bisicos para construir interfaces de base Web para aplicaciones. La tecnologia de servlets proporciona un modelo de prograrnacidn comGn que es tambiCn la base de las Piginas JavaServer. En capitdo anterior, hemos visto un andisis de las aplicaciones Web y 10s contenedores Web, en el que hemos repasado 10s requisitos de prograrnaci6n y estructura bisica de las aplicaciones Web. DespuCs nos hernos centrado en presentar 10s principios bisicos de 10s contenedores Web y las aplicaciones Web, y en c6rno las aplicaciones Web pueden ser programadas para rnejorar el proceso de solicitud-respuesta HTTP. El objetivo de 10s siguientes capitulos es presentar el API Java Servlet 2.3, que puede ser descargado desde http://java.sun.com/productS/servlet. Este API inchye dos paquetes: j avax .servlet y j avax. servlet .http.

Fijese en que el paquete javaxsmlet tiene dos subpaquetes para JSP (javax.servlet.jsp) y las etiquetas de adaptaci6n JSP (jsp.servlet.jsp.tagext). Estos paquetes s e r h analizados a partir del capitulo 10.
Analizaremos el API Java Servlet en cuatro pasos:

O Irnplernentacidn de servlets

Solicitudes y respuestas

O Sesibn, context0 y colaboracidn de servlet O Filtrado de solicitudes y respuestas

En este capitulo, nuestra intencidn es analizar 10s pasos primer0 y segundo; el tercer paso sera analizado en el capitulo 7 y el cuarso en el capitulo 8. Adicionalmente, estudtaremos 10s aspectos de despliegue en el capitulo 9.
En este capitulo, examinaremos 10s siguientes puntos:

Clases e interfaces para la irnplernentacidn de sewlets, incluido las excepciones de sewlet

O Configuracidn de sewlets O 0

El ciclo de vida de 10s sewlets


Solicitudes y respuestas

i-1 El modelo de programacidn del sewlet

Fijese en que este capitulo no pretende ser una referencia exhaustiva para 10s paquetes j a v a x . s e r v l e t y j a v a x . s e r v l e t .h t t p . En carnbio, analizarernos estos paquetes y 10s conceptos que 10s respaldan, concentrindonos en cdrno utilizar el API durante el desarrollo de las aplicaciones. La docurnentacidn del API Sewlet debe tenerlo a cerca mientras lee este capitulo. Puede acceder a esta docurnentacidn online en http://java .sun.com/products/servlet,/2.3/javadoc/index.htrn1.

Analisis del API Java Servlet


Corno ya hemos visto, el API Sewlet esti especificado en dos paquetes de extensidn Java: j a v a x . s e r v l e t y j a v a x . s e r v l e t .h t t p . Las clases e interfaces contenidas en el paquete j a v a x .s e r v l e t son independientes del protocolo, rnientras que el segundo paquete, j a v a x . s e r v l e t h t t p , contiene clases e interfaces que son especificas de HTTP. Observe que algunas de las clases/interfaces en j a v a x .s e r v l e t .h t t p arnplian las especificadas en el paquete javax. s e r v l e t .

La siguiente figura rnuestra el diagrarna de clase para algunas de las clases centrales del paquete j a v a x . s e r v l e t y algunas de sus asociaciones:

mterfaz ModeloThreadUnico

I I t
lnterfaz RqJLIe~taSeNlet
-

t
mterfaz SolicitudSelvi>

I
I

'

I
I

mterfaz Sewietbntext

t
StrearnSal~da StreamSalida StrearnEntrada StreamEntrada

mterfaz LanzadorSolicitud

Las flechas continuas representan asociaciones, mientras que las flechas discontinuas indican dependencias. Una asociacidn puede ser herencia, composicidn o incluso navegabilidad. La dependencia indica algun tip0 de combinacidn entre clases. Por ejemplo, la flecha discontinua que va desde la interfaz javax.servlet.Servlet basta javax.servlet.ServletRequest indica que el primero depende del ultimo y cualquier cambio en el primero depende del riltimo, y cualquier cambio en la Lltima definicidn de interfaz provoca cambios en el primero.

Programacion de servlets
La siguiente figura muestra algunas de las clases/interfaces del paquete j a v a x . s ervlet .ht tp:
-

intern

lnterfaz escuchante de eventos Escuchantede asociacion de sesion http I


-

~nterfaz RespuestaServletHttp

ava lo Ser~al~zable Sol~c~tudServleHtt

va lo Ser~al~zable

o..*

Cookle clonable Cookie

A ~nterfaz Sesi6nHttp
-

Observe que el contenedor rnantiene todas estas asociaciones, siernpre y cuando este' utilizando el paquete ja v a x . s e r v l e t . h t t p . Sin embargo, si estd construyendo servlets especializados que a : . s*r 1.1 * t , tendra' que rnantener algunas de las asociaciones. arnplien las clases del paquete 1a "
Estos diagramas no representan el API Sewlet completo. Para una mayor sencillez, estas figuras s610 destacan aquellas clases/interfaces que son necesarias para proporcionar un anilisis de este API. Presentaremos la parte restante del API durante 10s siguientes capitulos. iCuil es el prop6sito de todas estas interfaces y clases? Consideremos las siguientes cuestiones:
O

iC6mo gestiona el contenedor Web el ciclo de vida de 10s senlets? iC6mo pueden 10s senlets participar en este ciclo de vida? iC6mo implementamos la bgica de aplicaci6n? La 16gica de aplicaci6n en senlets es la &ica de programaci6n para responder a las solicitudes HTTP. Dependiendo de la arquitectura y complejidad de las aplicaciones, h a podria ser acceder a bases de datos, invocar 10s senicios de diversos EJB u otros componentes de capa media, o utilizar JMS para enviar mensajes a otras aplicaciones de empresa, etc. iC6mo leemos solicitudes HTTP y c6mo generamos respuestas HTTP? i C 6 m o tratamos las excepciones en 10s senlets? iC6mo pueden 10s sewlets interactuar con su entorno?

O O

N o intentaremos responder a estas preguntas en este momento pero, despuks de leer este capitulo, podremos responderlas. La siguiente tabla ofrece un anilisis del API Java Senlet, que seri examinado con detalle en breve. En esta tabla, varias intefaces/clases estin agrupadas segGn su prop6sito y uso (que estudiaremos en un momento). Las interfaces aparecen en cursiva, mientras que las clases (ya sean abstractas o no) y excepciones aparecen en fuente normal. Las adiciones a1 API Senlet de la versi6n 2.3 estin marcadas con un asterisco (:'):

Capitulo 6

Implementaci6n de servlet

javax.servlet.Servlet javax.servlet.Sir~gleThreadMode1 j a v a x . s e r v l e t .GenericServlet


javax.servlet.http.HttpServ1et

Configuraci6n de servlet Excepciones servlet Solicitudes y respuestas

j avax. s e r v l e t . S e r v l e t C o r ~ f i g javax.servlet.ServletExceptior~ j avax. s e r v l e t . U n a v a i l a b l e E x c e p t i o r ~ javax.servlet.http.HttpServ1etRequest javax.servlet.http.HttpServletRequestWrapper(*) javax.serv1et.http.HttpServletResporjse


javax.servlet.http.HttpServletRespor~s~eWrapper

j avax. servlet. ServletIr~putStrearn i t )


javax.servlet.Servlet0utputStrearn

javax.servlet.Serv1etRequest
javax.servlet.ServletRequestWrapper
j+)

javax.servlet.ServletRespor~se javax.servlet.Serv1etResponseWrapper javax.servlet.http.HttpSessior~


javax.servlet.http.HttpSessior~Activatior~Listerer (+) javax.servlet.http.HttpSessior~AttributeListener i t !
( * )

j avax. servlet. http. H t t p S e s s i o r ~ B i r ~ d i r ~ g L i s t e r ~ e r j a v a x . servlet. http. H t t p S e s s i o n B i r ~ d i r ~ g E v e r ~ t j avax. servlet. http. HttpSessionEvent it)
( * )

javax. servlet . h t t p . H t t p S e s s i o r ~ L i s t e r e r

Contexto de servlet

javax.servlet.Serv1etContext

javax. servlet. S e r v l e t C o r ~ t e x t A t t r i b u t e E v e r t i t ) javax.servlet.ServletContextAttributeLister~er javax. servlet. ServletCor~textEver~t(


* )

(*)

j avax. servlet. ServletCor~textListerer i t

Colaboraci6n de servlet Filtrado

javax.serv1et.RequestDispatcher javax. servlet. Filter


( * )
( + )

javax. servlet. Filterchain javax. servlet. FilterCorifig

it)

Varios

j a v a x . s e r v l e t .h t t p . C o o k i e
javax.servlet.http.HttpUti1s

Programacion de servlets
Los servidores Web con las implementaciones de Java Servlet, como Tomcat, WebLogic, Orion, iPlanet, JRun, etc., utilizan la mayoria de las interfaces y clases que aparecen en la tabla anterior. De hecho, aparte de las diversas interfaces escuchadoras de la tabla, s61o queda una clase abstracta ( j a v a x . s e r v l e t . h t t p . H t t p S e r v l e t ) yunainterfaz(javax. s e r v l e t . F i 1 t e r ) p a r a implementar cuando construya aplicaciones Web. El contenedor crea el resto de 10s objetos de periodo de ejecuci6n que son parte de su aplicaci6n. iPor q u i ocurre asi? U n contenedor Web es un marco de aplicacion con un entorno de periodo de aplicaci6n. En el marco, 10s objetos de aplicaciones son creados e invocados por el periodo de ejecuci6n. Mientras invoca 10s mitodos sobre 10s objetos de aplicaci6n, el contenedor tiene que construir 10s objetos para 10s argumentos. Por ejemplo, consideremos el G r e e t i n g s e r v l e t del capitulo anterior. En este servlet, el contenedor crea y pasa 10s o b j e t o s ~ t t p s e r v l e t ~ e q u ey sH t t t p S e r v l e t R e s p o n s e como argumentos a1 r n i t o d o d o ~ o s (t ) :
protectd v c i d doPost(HttpServ1etRequest request, HttpServletResponse responce) t h r ~ w s ServletExceotion, IOException {

Del mismo modo, el contenedor crea todos 10s demis objetos (corno s e r v l e t c o n f i g , S e r v l e t c o n t e x t , H t t p S e s s i o n , etc.) a 10s que un servlet puede acceder, directao indirectamente. La tabla anterior clasifica las clases/interfaces de 10s paquetes j a v a x . s e r v l e t y j a v a x .s e r v l e t .h t t p , basindose en su funcion en el desarrollo de aplicaciones Web. Por lo tanto, examinemos ahora esta clasificacidn rnis detenidamente: Implementaci6n de servlet Las clases/interfaces de esta categoria estin destinadas a implementar servlets. Por ejemplo, la clase G r e e t i n g s e r v l e t del capitulo anterior amplia la c l a s e ~ t t p s r e v l e t. Para desarrollar nuestra propios servlets, implementariamos uno o rnis mitodos de estas clases/interfaces. Cuando desplegamos semlets, el contenedor Web invoca estos mttodos para controlar su ciclo de vida y para ejecutar la 16gica de aplicaci6n.
0

Configuraci6n de servlet La interfaz s e r v l e t c o n f i g pertenece a esta categoria. El API Servlet ofrece varios medios de acceder a1 objeto s e r v l e t c o n f i g asociado a un servlet. Este objeto proporciona acceso a ciertos parametros de inicializacion que pueden ser configurados al desplegar un servlet. Demostraremos c6mo se puede realizar esto mas adelante, en este mismo capitulo.

0 Excepciones servlet El API JavaServlet especifica dos excepciones: S e r v l e t E x c e p t i o n y U n a v a i l a b l e E x c e p c t i o n . Habitualmente, 10s servlets lanzan estas excepciones, que el contenedor captura luego para ejecutar un apropiado manejo de errores.

o Solicitudes y respuestas
Hay cuatro interfaces y dos clases abstractas en esta categoria. Estos objetos proporcionan mttodos para acceder a la conexion cliente y las corrientes subyacentes de entrada y salida asociadas a ista. Utilizando estos objetos, podemos leer datos de la entrada y escribir datos de vuelta a1 cliente. Ademis de las anteriores, la especificacih Servlet 2.3 introduce clases envoltorio para las clases
ServletRequest,ServletResponse,http.HttpServletRequesty

h t t p .H t t p S e r v l e t R e s p o n s e (corno hemos visto en la tabla en las nombres de clases terminados en "Wrapper"). Aunque todas estas clases son abstractas, no contienen en realidad ninguna funcionalidad. Examinaremos la funcidn de estas clases envoltorio rnis adelante en este capitulo.
0 Localizaci6n de sesi6n La localizaci6n de sesi6n es una de las partes esenciales del desarrollo de aplicaciones Web. Como veremos en el capitulo 7, que es el protocolo fundamental para las aplicaciones Web, no tiene

estado. Como resultado, las aplicaciones Web no pueden reconocer multiples solicitudes del rnismo cliente HTTP originandose del mismo lugar. La noci6n de sesi6n proporciona esta abstracci6n. En tirminos sencillos, una sesi6n le perrnite agrupar solicitudes en un grupo reunido. Ademis, la gesti6n de sesiones tambikn irnplica la asociaci6n de datos con cada sesi6n. Al API Servlet especifica la interfaz j avax . servlet .Httpsession para proporcionar esta abstraction. Aprenderernos mas sobre sesiones en el proximo capitulo.
0

Contexto de servlet La nocion de contexto de servlet esti intimamente asociada a la noci6n de aplicaci6n Web. La interfaz j avax . servlet . servletcontext permite a 10s servlets de una aplicaci6n cornpartir datos. Tambiin ofrece mitodos con 10s que 10s servlets pueden acceder al contenedor Web host. Utilizando el objeto servletcontext,un servlet puede registrar eventos, obtener referencias URL a 10s recursos y fijar y almacenar atributos a 10s que puedan acceder otros servlets del contexto. Trataremos el contexto de servlet en el siguiente capitulo. Colaboraci6n de servlet El API Servlet tambiin proporciona una interfaz (~equest Dispat cher) con la que un servlet puede invocar otro servlet, una JSP o incluso un recurso estitico como una pigina HTML. Este rnecanisrno le ayuda a controlar el flujo de 16gica de mdtiples servlets y piginas JSP programiticarnente; lo estudiaremos con detalle en el capitulo 7.

Filtrado El API Servlet tiene un mecanismo con el que podemos introducir c6digo (Ilamado filtro) para participar en el proceso solicitud/respuesta del contenedor. Los filtros son una nueva caracteristica del API Java Servlet versi6n 2.3. Generalmente, no crean solicitudes/respuestas; en su lugar, rnodifican o adaptan solicitudes y respuestas desde y hacia un recurso Web, que puede tener contenido estitico o dinimico. Estudiaremos 10s filtros mis detenidamente en el capitulo 8. Otros API varios En esta categoria, encontrara dos clases: http .Cookie,que puede utilizar para crear cookies y http .HttpUtils,que proporciona mitodos ayudantes varios. Encontrari algunos ejemplos de estas clases en el siguiente capitulo.

En las siguientes secciones, analizarernos detenidamente las cuatro primeras categorias.

Implementation de servlet
Comencemos examinando de cerca las clases e interfaces utilizadas para irnplementar servlets.
/ '

La interfaz servlet
public interface Servlet

Esta interfaz especifica el contrato entre el contenedor Web y un servlet. En el paradigma orientado a1 objeto, un objeto puede cornunicar con otro siempre que el primer objeto pueda referenciar a1 segundo objeto con una interfaz conocida (no es necesario que conozca el nombre de la verdadera clase de implernentacion). En el caso del API Servlet, j avax . servlet . servlet es la interfaz que 10s contenedores utilizan para referenciar a servlets.

Programacion de servlets
Cuando escriba un servlet, debe implementar esta interfaz directa o indirectamente. Probablemente siempre implemente la interfaz indirectamente ampliando la clase j a v a x s e r v l e t .G e n e r i c s e r v l e t o laclasejavax. s e r v l e t . h t t p . ~ t t p ~ e r v l e t .

A1 implementar la interfaz j a v a x . s e r v l e t . s e r v l e t , 10s siguientes cinco metodos deben set implementados:


public public public public public void init(Serv1etConfig config) void service(Serv1etRequest request, ServletResponse response) void destroy 0 ServletConfig getServletConfig() String getServletInfo0

El metodo init()
public void init(Serv1etConfig config) throws ServletException

Una vez sue el servlet ha sido instanciado, el contenedor Web invoca el metodo i n i t ( ) . El obietivo de este metodo es permitir a un servlet realizar cualquier inicializacion requerida antes de ser invocado en solicitudes HTTP. El contenedor pasa un objeto de tip0 s e r v l e t c o n f i g a1 metodo i n i t ( ) y, como veremos mis tarde, un servlet puede acceder a sus datos de configuracion utilizando el objeto caso ne~ de queno se s e r v l e t c o n f i g . El m e t o d o i n i t ( ) lanzauna e x c e p c i 6 n ~ e ~ v l e t ~ x c e p t i o n e complete de forma normal. La especificacion Servlet garantiza que el metodo i n i t ( ) seri invocado exactamente una vez en una instancia dada del servlet y el metodo i n i t ( ) podri completar (siempre que no lance una S e r v l e t E x c e p t i o n ) antes de que ninguna solicitud sea pasada a1 servlet. Algunas de las tareas tipicas que pueden ser implementadas en el metodo i n i t
0
()

son:

Leer 10s datos de configuracion de recursos persistentes como archivos de configuraci6n

O Leer parimetros de inicializaci6n utilizando el objeto s e r v l e t c o n f i g


L I

Inicializar actividades antiguas como registrar un driver de base de datos, una reserva de conexion o un servicio de registro

El metodo service()
public void service(Serv1etRequest request, ServletResponse response) throws ServletException , IOException

~ s t es e el punto de entrada para ejecutar la 16gica de aplicacion en un servlet. El contenedor invoca este metodo en respuesta a solicitudes entrantes. S d o despuis de que el servlet haya sido inicializado con kxito, sera invocado el metodo s e r v i c e ( ) . El metodo s e r v i c e ( ) acepta dos argumentos, implementado las interfaces ja v a x . s e r v l e t .S e r v l e t y ja v a x . s e r v l e t .S e r v l e t ~ e s p o n s e r e s p e c t i v a m e n t e . E l objeto solicitud proporciona metodos para acceder a 10s datos originales de solicitud y el objeto respuesta proporciona mktodos con 10s que el servlet puede construir una respuesta.

El metodo destroy()
public void destroy
()

Este contenedor invoca este metodo antes de eliminar una instancia de servlet fuera de servicio. Esto puede suceder si necesita liberar memoria o si el servidor Web esti siendo cerrado. Antes de que el

Capitulo 6
contenedor invoque este metodo, dara tiempo a 10s restantes hilos s e r v i c e ( ) para que terminen de ejecutar (sujetos a un period0 de tiempo limite), de mod0 que el metodo d e s t r o y ( ) no sea invocado mientras se produce una llamada s e r v i c e ( ) . Despues de invocar el metodo d e s t r o y ( ) , el contenedor no encamina dirige el servlet. Las actividades que pueden ser implementadas en el metodo d e s t r o y ( ) incluyen:
D Realizar tareas de limpieza, como cerrar cualquier recurso abierto, cerrar una reserva de

conexiones, o incluso informar a otra aplicaci6n/sistema que el servlet ya no esta de servicio

O Mantener cualquier estado asociado a un servlet

El metodo getsewletconfig()
public ServletConfig getServletConfig()

Este mktodo debe ser implementado para devolver el s e r v l e t c o n f i g que fue pasado a1 servlet durante el metodo i n i t ( ) .

public S t r i n g g e t S e r v l e t I n i o 0

Este metodo debe devolver un objeto s t r i ? g que contenga informaci6n sobre el senlet (por ejemplo, autor, fecha de creacibn, descripci6n, etc.). Esta esta disponible para el contenedor Web, en caso de deseara mostrar, por ejemplo, una lista de servlets instalados junto con sus descripciones.

La clase GenericServlet
public abstract class GenericServlet implements Servlet, Servletconfig, Serializable

La clase G e n e r i c S e r v l e t proporciona una implementaci6n bisica de la interfaz s e r v l e t . ~ s t es a una clase abstracta y todas las subclases deben implementar el metodo s e r v i c e ( ) . Esta clase abstracta tiene 10s siguientes metodos ademis delos declarados en j a v a x . s e r v l e t .s e r v l e t y javax.serv1et.ServletConfig:
public init ( ) public void log(String message) public void log (String message, Throwable t)

El metodo init ( s e r v l e t c o n f i g c o n f i g ) almacenael o b j e t o s e r v l e t C o n f i g e n u n a v a r i a b l e de instancia privada transitoria (llamada c o n f i g ) . Puede utilizar el metodo g e t s e r v l e t c o n f i g ( ) para acceder a este objeto. Sin embargo, si elige ignorar este metodo, debe incluir una llamada a s u p e r . i n i t ( c o n f i g ) .Alternativamente, puede ignorar el metodo sin argument0 i n i t ( ) de laclase GenericServlet. La c l a s e ~ e n e r i c ~ e r v ltambikn et implementala interfaz S e r v l e t c o n f i g . Esto permite a1 desarrollador de servlet invocar 10s mktodos s e r v l e t c o n f i g directamente sin tener que obtener primer0 un objeto s e r v l e t c o n f i g . Estos metodos son g e t I n i t p a r a m e t e r ( ) , g e t I n i t P a r a m e t e r N a m e s 0 , g e t s e r v l e t c o n t e x t ( ) y g e t S e r v l e t N a m e ( ) .Cadaunodeestos metodos delega las llamadas en 10s mitodos respectivos del objeto s e r v l e r c o n f i g almacenado.

Programacion de servlets
La clase G e n e r i c C o n f i g tambiin incluye dos metodos para escribir a un registro de servlet, que invoca 10s mitodos correspondientes en s e r v l e t c o n t e x t . El primer metodo, l o g ( S t r i n g m s g ) , escribe el nombre del servlet y el argument0 msg en el registro del contenedor Web. El otro mitodo, l o g ( S t r i n g m s g , T h r o w a b l e c a u s e ) , incluye una traza de pila para la excepci6n dada T h r o w a b l e ademis del nombre del servlet y el mensaje. La verdadera implementaci6n del mecanismo de registro es especifica del contenedor, aunque la mayoria de 10s contendores utilizan archivos de textos para 10s registros.

La interfaz SingleThreadModel
public interface SingleThreadModel

El API Servlet especifica una interfaz de registro especjal llamada javax.servlet.SingleThreadMode1. Durante la vida de un servlet que no implementa esta interfaz, el contenedor puede enviar multiples solicitudes de servicio en diferentes hilos a una unica instancia. Esto significa que la implementacidn del metodo s e r v i c e ( ) debe estar a salvo de hilos. Sin embargo, icual es la alternativa si el mitodo s e r v i c e ( ) no esti a salvo de hilos? El API Java Servlet especifica la interfaz S i n g l e T h r e a d M o d e l con este prop6sito. Los servlets pueden implementar la interfaz S i n g l e T h r e a d M o d e 1 (ademis de implementar la interfaz j a v a x s e r v l e t S e r v l e t o ampliar una de sus clases de implementaci6n) con el objetivo de informar a1 contenedor de que debe asegurarse de que s610 un hilo esti ejecutando el metodo s e r v i c e ( ) del servlet en un momento dado.

Para servlets S i n g l e T h r e a d M o d e l , 10s contenedores deben seguir uno de 10s siguientes enfoques para asegurar que cada instancia de servlet es invocada en un hilo independiente:
0 Reserva de instancias En este enfoque, el contenedor mantiene una reserva de instancias de servlet. Para cada solicitud entrante, el contenedor destina una instancia de servlet de la reserva y sobre la conclusi6n del servicio, el contenedor devuelve la instancia a la reserva.
0

Serializaci6n de solicitudes En este enfoque, el contenedor mantiene una unica instancia del servlet. Sin embargo, como el contenedor no puede enviar multiples solicitudes a la instancia a la vez, el contenedor serializa las solicitudes. Esto significa que las nuevas solicitudes se mantendrin a la espera mientras que la solicitud actual es servida.

En realidad, una combinacicin de estos dos enfoques es m6s pragmitica, de modo que el contendor podria mantener un numero razonable de instancias en la reserva, mientras que todavia serializaria las solicitudes si el nlimero de solicitudes excediera el numero de instancias en la reserva. Fijese en que el modelo de hilo unico ( S i n g l e T h r e a d M o d e l ) es intensivo en recursos, especialmente si se espera un gran numero de solicitudes concurrentes para el servlet. El efecto del S i n g l e T h r e a d M o d e l es que el contenedor invoca el metodo s e r v i c e ( ) en un bloque sincronizado. Esto es equivalente a utilizar la palabra clave s y n c h r o n i z e d para el mitodo s e r v i c e ( ) del servlet. Consecuentemente, cuando hay cientos o incluso miles de solicitudes concurrentes en el contenedor Web, el contenedor puede serializar las solicitudes a la misma instancia del servlet o crear tantas instancias como solicitudes. En el primer caso, la capacidad del contendor para procesar las solicitudes concurrentes se veri severamente perturbada debido a la serializaci6n. En el ultimo caso, el contenedor se encuentra con mis asignaci6n de objeto (que incluye m6s sobregasto de creaci6n de objetos y gasto de memoria).

Capitulo 6
Sin embargo, en casos en 10s que s61o algunas instrucciones del metodo s e r v i c e ( ) no estin a salvo de hilos, debe considerar reducir el alcance de la sincronizaci6n y sincronizar explicitamente esos bloques utilizando la palabra clave s y n c h r o n i z e d . Cuanto mis cortos sean 10s bloques, mejor puede ser el rendimiento de este enfoque.

Siempre debemos considerar la posibilidad de volver a disehar nuestras aplicaciones para evitar el modelo de hilo h i c o , SingleThreadModel, o la sincronizaci6n de hilos. Si no podemos evitarlas, es importante ser consciente de las implicaciones de rendimiento. Con cualquier c6digo de sincronizaci6n de hilos est6 bloqueando potencialmente un hilo de contenedor Web.

La clase HttpServlet
public abstract class HttpServlet extends GenericServlet implements Serializable

La c l a s e H t t p S e r v l e t a m p l j a G e n e r i c S e r v l e t y proporcionauna implementaci6n especifica de H T T P de la interfaz Senlet. Esta seri probablemente la clase que todos 10s senlets ampliarin. Esta clase especifica 10s siguientes metodos:
public void service(Serv1etRequest request, ServletResponse response) protected void service(HttpServ1etRequest request, HttpServletResponse response) protected void doGet (HttpServletRequest request, HttpServletResponse response) protected void doPost(HttpServ1etRequest request, HttpServletResponse response) protected void doHead(HttpServ1etRequest request, HttpServletResponse response) protected void doDelete (HttpServletRequest request, HttpServletResponse response) protected void dooptions (HttpServletRequest request, HttpServletResponse response) protected void doput (HttpServletRequest request, HttpServletResponse response) protected void doTrace(HttpServ1etRequest request, HttpServletResponse response) protected long getLastModified(HttpServ1etRequest request)

Los metodos service()


El H t t p S e r v l e t tiene dos variantes de este metodo:
public void service(Serv1etRequest request, ServletResponse response) throws ServletException, IOException

~ s t es a unaimplementaci6n del metodo s e r v i c e ( ) en G e n e r i c S e r v l e t . Este metodo emite 10s objetos de solicitud y respuesta a H t t p S e r v l e t R e q u e s t y H t t p S e r v l e t R e s p o n s e , e invocael siguiente metodo sobrecargado s e r v i c e ( ) . Por lo tanto, no debe ignorar el mitodo anterior.
protected void service(HttpServ1etRequest request, HttpServletResponse response) throws ServletException, IOException

Este metodo sobrecargado toma objetos solicitud y respuesta especificos de HTTP, y es invocado por el primer m i t o d o anterior. H t t p S e r v l e t irnplementa este mitodo para ser un lanzador de solicitudes HTTP. C o m o veri mis adelante en este mismo capitulo, la interfaz j a v a x . s e r v l e t .S e r v l e t R e q u e s t p r o p o r c i o n a u n m ~ t o d o g e t ~ e t h o (d ) quedevuelveel tipode metodo H T T P asociado a la solicitud. Por ejemplo, para solicitudes GET, este metodo devuelve "GET" como una cadena. El metodo s e r v i c e ( ) utiliza esta cadena para delegar la solicitud en uno de 10s m e t o d o s d o x x x ( ) . J a v a x . s e r v l e t h t t p . H t t p S e r v l e t pr~~orcionairnp~ementaciones pordefecto a todos estos metodos.

Programacion de servlets
En general, debe evitar ignorar este mitodo ya que afecta a1 comportamiento por defecto del metodo s e r v i c e ( ) . La Gnica situacion que requiere ignorar este metodo se produce cuando se quiere cambiar el comportamiento por defecto o cuando se quiere incluir procesamiento adicional comGn a todos 10s ( ) . Incluso en esos casos, debe considerar incluir una llamada a s u p e r . s e r v i c e ( ) en metodos ~ O X X X sus servlets. La secuencia de llamadas de metodo cuando el contenedor recibe una solicitud para un servlet es la siguiente:

u El contenedor invoca el metodo s e r v i c e


0

El metodo pGblico s e r v i c e ( ) invoca el metodo protegido s e r v i c e ( ) despues de emitir 10s argumentosa H t t p S e r v l e t R e q u e s t y H t t p S e r v l e t R e s p o n s e r e s p e c t i v a m e n t e El metodo protegido s e r v i c e ( ) invoca uno de 10s mktodos ~ O X X X ( ) , dependiendo del tip0 del metodo de solicitud H T T P

Los metodos doXXX()


La clase ~ t t e r pv l~ e t implementa 10s siguientes metodos protegidos, uno para cada metodo de solicitud HTTP:
protected void doGet (HttpSe~letRequestrequest, HttpServletResponse response) throws ServletException, IOException protected void doPost(HttpServ1etRequest request, HttpServletResponse response) throws ServletException, IOException protected void doHead(HttpServ1etRequest request, HttpServletResponse response) throws ServletException, IOException protected void doDelete(HttpServ1etRequest request, HttpServletResponse response) throws ServletException, IOException protected void doOptions(HttpServ1etRequest request, HttpServletResponse response) throws ServletException, IOException protected void doput (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException protected void doTrace(HttpServ1etRequest request, HttpServletResponse response) throws ServletException, IOException

La firma de cada uno de 10s mktodos ~ O X X X ( ) es la misma que la del metodo protegido s e r v i c e ( ) anterior; cada uno toma argumentos H t t p S e r v l e t R e q u e s t y H t t p S e r v l e t R e s p o n s e , lanza ServletExceptionyIOException. La clase H t t p e ~r v l e t proporciona implementaciones adecuadas para 10s mktodos TRACE y OPTIONS, y n o es necesario que sus servlets ignoren d o T r a c e ( ) y d o o p t i o n s ( ) . Para 10s otros cinco mktodos, la clase H t t p s e r v l e t proporciona implementaciones que devuelven errores H H T P . Para el caso de contenedores sometidos a HTTP 1.0, estos mktodos devuelven un error HTTP con c6digo de estado 400, indicando que la solicitud enviada por el cliente es sintacticamente incorrecta. Para 10s contenedores que se ajustan a HTTP 1.1, estos metodos devuelven un error H T T P con codigo de estado 405, indicando que el metodo H T T P solicitado no esta permitido para este servlet. de Esta clase utiliza el m ~ t o d o g e t ~ r o t o (c) o ~ la interfaz j a v a x . s e r v l e t S e r v l e t R e q u e s t para determinar el protocolo.

Dependiendo de su aplicaci6n, debe determinar 10s mktodos HTI'P que deben ser apoyados por su servlet e ignorar ( ) correspondientes (except0 10s de 10s metodos TRACE y OPTIONS). consecuentemente 10s metodos ~ O X X X

El metodo getlastModified()
protected long getLastModified(HttpServ1etRequest req)

Capitulo 6
Este mCtodo implementa una operaci6n condicional get. Por ejemplo, debe devolver el momento en el que el servlet fue modificado por Gltima vez en milisegundos desde el 1 de Enero, 1970 00:00:00 GMT. La implementacih por defect0 devuelve un numero negativo (-1) indicando que el momento de modificaci6n es desconocido. H T T P 1.1 alberga la nocion de solicitudes condicionales GET. La cabecera 1f-Modi f i e d - s i n c e es una de las cabeceras que convierte a una solicitud en condicional. Los clientes que se ajustan a HTTP 1.1 pueden enviar esta cabecera con un campo de fecha (por ejemplo: I f -Modif i e d - s i n c e : S a t , 01 J a n 2 000 00 : 00 : 00 GMT).Esta cabecera indica a1 servidor que si el recurso solicitado no ha sido modificado desde la fecha indicada en la cabecera, el contenedor Web no necesita invocar el mCtodo d o G e t ( ) , puesto que todas las versiones actuales de navegadores de uso comun como Internet Explorer 5.5, Netscape 6.0, y Opera 5.1 se ajustan a H T T P 1.1 y se aprovechan de esta cabecera. Sus servlets pueden ignorar este metodo para controlar la memorizaci6n en cache de piginas generadas por el mCtodo doGet ( ) .

Configuracion de servlets
En el API Java Servlet, 10s objetos j a v a x . s e r v l e t S e r v l e t c o n f i g representan la configuracidn de un servlet. La informaci6n de configuracibn contiene parimetros de inicializacion (un conjunto de pares nombre/valor), el nombre del servlet y un objeto j a v a x . s e r v l e t .s e r v l e t c o n t e x t , que ofrece la informaci6n del servlet sobre el contenedor. Los parimetros de inicializacidn y el nombre de un servlet pueden ser especificados en el descriptor de despliegue (el archivo Web. xml), por ejemplo:

Este ejemplo registra un servlet de nombre a d m i n y especifica dos parametros de inicializaci6n, e m a i l y helpURL. El contenedor Web lee esta informaci6n, y la pone a disposicion de com.wrox. a d m i n . ~ d m i n ~ e r v l medianteelobjetojavax. et s e r v l e t . servletConfig.Si queremos cambiar estos parimetros, podemos hacerlo sin tener que volver a compilar el servlet. Aprenderemos mis sobre este enfoque en el capitulo 9.

El mecanismo del descriptor de despliegue fue introducido en la especificacio'n Servlet 2.2. Los contenedores W e b (llamados entonces motores de servlet) que se ajustan a versiones antiguas de la especificacion, proporcionan medios especificos del proveedor (como archivos apropiados) para espec;ficar 10s pardmetros de inicializacidn.

La interfaz ServletConfig
public interface ServletConfig

Programacion de servlets
Corno hernos ya visto cuando hemos analizado la clase G e n e r i c S e r v l e t , esta interfaz especifica 10s siguientes rnetodos:
public public public public String getInitParameter(String name) Enumeration getInitParameterNames() ServletContext getServletContext() String getServletName ( )

El metodo gethitparameter()
public String getInitParameter(String name)

Este mCtodo devuelve el valor de un parirnetro llarnado inicializacidn o n u 1 1si el pardmetro especificado n o existe. En el ejernplo anterior, a1 invocar el rnCtodo g e t ~ n i t ~ a r a m e t con e r " e m a i l " como argumento, se obtiene el valor " a d m i n . @ a d m i n w r o x com".

El metodo getlnitParameterNames()
public Enumeration getInitParameterNames()

Este mktodo devuelve una enurneraci6n de todos 10s parimetros de inicializaci6n de un sewlet. U t i k a n d o esta enurneraci6n, puede obtener 10s nornbres de todos 10s parimetros de enurneraci6n sucesivarnente. Si n o hay parirnetros de inicializaci6n e ~ ~ e c i f i c a d oeste s , metodo devuelve una enurneraci6n vacia. En el ejernplo anterior, invocar el rnktodo g e t I n i t P a r a m e t e r N a m e s ( ) devuelve una enurneraci6n que contiene dos objetos S t r i n g : " e m a i l " y " h e l p U R L U .

El metodo getsewletcontext()
public ServletContext getServletContext0

Este rnktodo devuelve una referencia a1 objeto s e r v l e t c o n t e x t asociado con la aplicaci6n Web. j a v a x . s e r v l e t .S e r v l e t c o n t e x t es analizadoconrnis detalles enel siguientecapitulo.

El metodo getSewletName()
public String getServletName()

Este metodo devuelve el nornbre asignado a un sewlet en su descriptor de despliegue. Si n o hay ningdn nombre especificado, kste devuelve en su lugar el nombre de clase de sewlet.

Obtener una referencia a ServletConfig


En el API Java Sewlet, un sewlet puede obtener una referencia al objeto j a v a x . s e r v l e t .~ervlet~onfigdelossiguientesrnodos:

Durante la inicializacion del sewlet


Corno hemos analizado anteriorrnente, 10s rnktodos i n i t ( ) de la interfaz s e r v l e t y la interfaz G e n e r i c S e r v l e t tienenunargurnentodetipos j a v a x . s e r v l e t . s e r v l e t c o n f i g . D u r a n t e l a inicializaci6n de un sewlet, el contenedor Web crea este argurnento y lo pasa el metodo i n i t ( ) . Cuando sustituye el m e t o d o i n i t ( ) ,puedeaccederalobjeto j a v a x . s e r v l e t .s e r v l e t c o n f i g .

Capitulo 6
Sin embargo, cuando ignora el mCtodo anterior i n i t ( ) en la clase G e n e r i c s e r v l e t , debe invocar e x p l i c i t a m e n t e ~ u ~. eirn i t ( ) como sigue:
public i n i t ( ServletConfig config)
{

super. i n i t ( c o n f i q ) ; //
\

Inicializaci6n

ayui

La llamada a s u p e r . i n i t ( c o n f i g ) asegura que la c l a s e ~ e n e r i c ~ e r v lrecibe et una referencia a1 o b j e t o s e r v l e t c o n f i g . La irnplementacidn de la c l a s e ~ e n e r i c ~ e r v lmantiene et en realidaduna referencia a1 objeto s e r v l e t c o n f i g (como una variable de instancia transitoria) y requiere que s u p e r . i n i t ( c o n f i g ) sea invocado en subclases.

Utilizar el metodo getsewletconfig()


Los servlets tambikn pueden acceder a1 objeto s e r v l e t c o n f i g invocando el mktodo g e t s e r v l e t c o n f i g ( ) . Estemktodoestiespecificadoenlainterfaz j a v a x . s e r v l e t .S e r v l e t . Alternativamente, 10s servlets que arnplian e l ~ e n e r i e cr ~ v l e t o su s u b c l a s e ~ t t pe s r v l e t tambikn pueden invocar 10s mCtodos de la interfaz s e r v l e t c o n f i g directamente. Esto se debe a que G e n e r i c S e r v l e t tambiknirnplementalainterfaz s e r v l e t c o n f i g .

Excepciones servlet
El paquete j a v a x .s e r v l e t especifica dos clases de excepciones: javax.servlet.ServletExceptionyjavax.servlet.UnavailableException.

La clase ServletException
public class ServletException extends java. lang. Exception

~ s t es a una excepci6n generica que puede ser lanzada por 10s rnktodos i n i t ( ) , s e r v i c e ( ) , ~ O X X X () y d e s t r o y ( ) . La clase proporciona 10s siguientes constructores:
public public ServletException ( ) ServletException (String message)

A1 crear objetos de tip0 s e r v l e t E x c e p t i o n , puede integrar cualquier excepci6n de aplicaci6n (Ilamada causa-raiz). Los contenedores utilizan la excepcidn causa-raiz con propdsitos de registro. Por ejemplo, puede integrar una excepci6n j a v a x . s q l .S Q L E x c e p ti o n en una excepcidn j a v a x .s e r v l e t .S e r v l e t E x c e p t i o n . Existen dos constructores adicionales para apoyar estas excepciones causa-raiz:
public public

ServletException(Throwab1e cause) ServletException(String message, Throwable cause)

El m k t o d o g e t ~ o o t ~ a u ( s )e devuelve la excepci6n causa-raiz:


public Throwable getRootCause()

Programacion de servlets

La clase UnavailableException
public class UnavailableException extends ServletException

javax . servlet .UnavailableExceptiones un tiPo especial deexcepci6nservlet. Puesto queeste servlet amplia j avax.servlet . ServletException,todos 10s metodos de servlet quepueden lanzar una exception j avax .servlet .Exception tambiin puedenlanzarunaexcepci6n javax.servlet.UnavailableException.
El objetivo es indicar a1 contenedor Web que el servlet no esti disponible bien de forma temporal o permanentemente. Esta clase especifica 10s siguientes constructores:
public UnavailableException(String message)

~ s t construye e una nueva excepci6n permanentemente indisponible con el mensaje dado:


public UnavailableException (String message, int seconds)

Esto construye una nueva excepci6n n o disponible con el mensaje dado. El argument0 seconds indica la duraci6n en segundos durante la cual el servlet no esti disponible. Analizaremos mis tarde el cornportamiento exacto del contenedor en fallos temporales y permanentes.

C o m o hernos visto anteriormente, el contenedor es un period0 de ejecuci6n que gestiona 10s servlets. De e s entre las diversas responsabilidades de un contenedor, la gestion del ciclo de vida es la mbs .caso de 10s servlets, 10s eventos de ciclo de vida estin especificados en la interfaz j avax . servlet .servlet del API Servlet. Aunque la gesti6n del ciclo de vida es una responsabilidad del contenedor, como desarrolladores de servlets, debemos asegurarnos de que nuestros servlets siguen el modelo de ciclo de vida y de que no son implementados en un modo que contradiga esta condici6n. Los metodos de la interfaz Servlet relevantes para el ciclo de vida del servlet son init ( ) , service ( ) y destroy ( ) . El ciclo de vida empieza cuando el contenedor invoca el metodo init() y termina cuando el contenedor invoca el mitodo destroy ( ) . El ciclo de vida de un servlet consiste en las siguientes etapas fundamentales:

Instanciacibn
El contenedor Web crea una instancia del servlet

Inicializacibn
El contenedor invoca el metodo init ( ) de la instancia

Revisibn
Si el contenedor tiene una solicitud para el servlet, invoca el metodo service ( ) de la instancia del servlet

Destruccibn
Antes de destruir la instancia, el contendor invoca el metodo destroy() de la instancia del servlet

N o disponible
La instancia es destruida y marcada para la recolecci6n de residuos

Capitulo 6
El diagrama de estado UML muestra las posibles transiciones en el ciclo de vida del servlet:

No exlste

Instanclac16nbasada en una sollcltud o en el arranque del contenedor

7 -

-1

lnstanc~ado

--

Fallo en ln~c~ac~on De vuelta a revlslon en caso d indisponibilidad temporal

L~berar

referenc~a

I
1

1
Sol~citud(es) HlTP de

1
Hilo de final

Fallo temporal o permanente

Fin de plazo limite o cierre del contenedor

El contenedor crea una instancia de servlet en respuesta a una solicitud HTTP entrante o en el arranque del contenedor. DespuPs de la instanciaci6n, el contenedor inicializa la instancia invocando su metodo i n i t ( ) . DespuCs de la inicializaci6n, la instancia de servlet esti preparada para servir solicitudes entrantes. El proposito de este proceso de inicializacion es cargar cualquier parimetro de inicializaci6n requerido para el servidor. Veremos c6mo se puede conseguir esto en la siguiente secci6n. Durante el proceso de inicializaci6n, una instancia de servlet puede lanzar una exception Servlet~xceptiono~navailable~xce~tion.~navailable~xceptionesunasubc~asede S e r v l e t E x c e p t i o n . Mientras q u e s e r v l e t E x c e p t i o n p u e d e ser utilizadaparaindicar fallos generales de inicializaci6n (como fallos a1 encontrar 10s parimetros de inicializacibn), U n a v a i l a b l e E x c e p t i o n se utiliza para informar sobre la no-disponibilidad de la instancia para servir solicitudes. Por ejemplo, si su servlet depende de un servidor RMI y esti verificando si el servidor es alcanzable para r e v i d n , su instancia de servlet puede lanzar una U n a v a i l a b l e E x c e p t i o n para indicar que esti temporal o permanentemente indisponible. Si su instancia de servlet determina que la nodisponibilidad debe ser temporal, puede que asi lo indique mientras construye la excepci6n U n a v a i l a b l e E x c e p t i o n , especificando el numero de segundos de indisponibilidad a1 constructor de la excepci6n. Cuando tiene lugar este fallo, el contenedor suspende todas las solicitudes a su servlet durante el periodo especificado y lo devuelve a su estado de disponibilidad a1 final del periodo. Si no especifica internamente una configuracidn de indisponibilidad, el servlet estari indisponible cuando se reinicie el contenedor. Una de las aplicaciones de esta excepci6n tiene lugar cuando uno de sus componentes o sistemas de segundo plano no esti accesible temporalmente. En general, si su 16gica de aplicaci6n es tal que ciertos fallos pueden ser resueltos reintentindolo despu6s de un rato, puede utilizar esta excepci6n. El contenedor garantiza que, antes de que se invoque el metodo s e r v i c e ( ) , el metodo i n i t ( ) podri ser completado y que, antes de que el servlet sea destruido, su metodo d e s t r o y ( ) seri invocado. El servlet puede l a n z a r s e r v l e t ~ x c e ~ t i ~ oU n n a v a i l a b l e E x c e p t i o durante n su metodo s e r v i c e ( ) , en cuyo caso el contenedor suspenderi las solicitudes para esa instancia temporal o permanentemente. Es importante que disefie sus servlets considerando fallos temporales y permanentes.

Programacion de servlets
En teoria, no hay nada que impida que un contenedor Web ejecute el ciclo de vida complete del servlet cada vez que un servlet es solicitado. En la prictica, 10s contenedores Web cargan e inicializan 10s servlets durante el arranque del contenedor o cuando el servlet es invocado por primera vez y mantienen esa instancia de servlet en la memoria para revisar todas las solicitudes que recibe. El contenedor puede decidir en cualquier momento liberar la referencia de servlet, finalizando asi el ciclo de vida del servlet. Esto podria ocurrir, por ejemplo, si el servlet no ha sido invocado durante un tiempo o si el contenedor se estd cerrando. Cuando esto sucede, el contenedor invoca el metodo destroy ( ) . En el modelo habitual de ciclo de vida de servlet, el contenedor Web crea una unica instancia de cada servlet. Pero, ique ocurre si el metodo service ( ) del servlet esta todavia ejecutandose cuando el contenedor Web recibe otra solicitud? Para 10s servlets que no implementan la interfaz j avax. servlet .SingleThreadModel,el contenedorinvoca lamismainstancia de servlet en cada hilo de solicitud. Por lo tanto, siempre es posible que el metodo service ( ) sea ejecutado en mas de un hilo, siendo necesario que el metodo service ( ) estk a salvo de hilos. Aparte de no acceder a recursos a salvo de hilos (como escribir a archivos), debemos tambien considerar mantener nuestros servlets sin estado (es decir, no definir ningun atributo en sus clases de servlet). A1 definir variables de instancias en nuestros servlets, debemos asegurarnos de que tales variables son manipuladas de modo seguro. Hemos analizado previamente el rendimiento de 10s servlets que implementan la interfaz j avax . s ervlet . SingleThreadModel.Recuerde que, paraestos servlets, el contenedorpuede serializar solicitudes o mantener una reserva de instancias de servlet y destinar cada solicitud a una instancia diferente de la reserva, o utilizar una combinaci6n de estas dos. El siguiente diagrama muestra la secuencia de eventos que representan un servlet durante su carga, revisando dos solicitudes en ripida sucesi6n y siendo despues descargado cuando el servidor se cierra:
Contenedor

'

Crear reserva de

lnstanclar servlet

Sollc~tud

lnvocar m e t o d o l n lt () -. - -

---4
---

4 Sewlet

Ejecutar

HTrP 1
Sol~c~tud HTrP 2 C~erre

*Destmar sollcltud a hllo

lnvocar metodoservlce

I
Destlnar sollcltud a hllo & --

-----,
-

'Ejecutar rews~on

Ejecutar revlslon

HTrP 1
/

/t-

10s h~los actlvos F~nal~zar reselva de h~los


-

*.

Respuesta

ocar metododestro

HTrP 2

*i Servlet destruido y la
YI

C~erre del contenedor

basura recog~da

Capitulo 6
Existe todavia otra situaci6n en la que un contenedor podria crear mbs de una instancia de un servlet: seria el caso en el que una clase servlet fuera afiadida en el descriptor de despliegue mbs de una vez, posiblemente con diferentes parbmetros de inicializacion. Puede que encuentre 10s anteriores enfoques de instanciaci6n bastante complejos. Para evitar problemas, sus servlets no deben asumir la instanciaci6n. Por ejemplo, no debemos asumir que la misma instancia de servlet se utilice para todas las solicitudes/clientes o que s61o un hilo ejecute un mitodo service ( ) a la vez.

Consideremos ahora un ejemplo, para comprender mejor el ciclo de vida del servlet. El ejemplo consiste , demuestra 10s diversos estados de un tipico servlet, en un h i c o servlet llamado Frea. k ~ e r v l e tque incluido la indisponibilidad.
Introduzcalasiguientefuenteen%BOOK-HOME~\ChO6\freakservlet\src\FreakServlet donde BOOK-HOME es el directorio raiz para su c6digo fuente:
, ' / Importar paquetes d e servlet i m ~ , o r tjavax.servlet.http.HttpServ1et; import javax.servlet.http.HttpServ1etRequest; import javax.servlet.http.HttpServ1etRespor~se; import javax.servlet.ServletExceptior~; i m p o r t javas.servlet.Unavai1ab1eExcepti0r~; /,' Importar otros paquetes Java import j a v a . io. IOException; i m p ~ r t j a v a . io. PrintWri ter;
public class FreakServlet extends HttpServlet { java.util.Vector states; j ava. util. Random random; int waitInterva1; public static final int DEFAULT WAIT INTERVAL public F r e a k S e r v l e t o ( states = new java.uti1 .Vector ( ) ; random = new j ava. util. Random( ) ; waitInterva1 = DEFAULT WAIT INTERVAL; ) ; states. add (createstate ("Ir1star1tiatior1")
I

.java,

10;

public void init ( ) throws ServletException ( states.add (createstate(states.addicreateStateo'Ir~itializatior~") ) ; String wait1ntervalString = getServletConfig( ) .getIr,itParameter("waitIr~terva1") ; if (waitIntervalString ! = null) ( waitIrlterva1 = new Integer (waitIntervalStrir~g) . ir~tvalue ( ) ;

I
protected void doGet(HttpServ1etRequest request, HttpServletResponse throws ServletException, IOException { if response)

(random.r!extBoolean ( ) ) { / / No disportible durante waitIr~terva1 segundos states.add(createState("Urlavailab1e from d o G e t V )) ; throw new UnavailableExceptior~ ("Ur~available from doGetM, wait.Irlterva1);

Programacion de servlets

states .add(createState ("Service"))

response. setConterjtType ( "text/htmll') ; Printwriter out = response.getWriter();


/ / enviar acuse a1 r~avegador out.println("<htmli"); o u t .println ("<meta http-equiv=\"Fragma\" out.println("<headiCtitle>");

content=\ "rio-cache\">" )

out .println I" FreakServlet: State History" ) ; o u t .printlr~ ( "</titlei</head>"); out.printlr~("<bodyi"); out.println("<hl>FreakServlet: State History</hl>");

for (int i = 0; i < states.size(); itt) { out.println("<p> " t states.elementAt(i)

"</p>");

public void d e s t r o y ( ) { states.add(createState("DestroyYY)); system. out .println ("Flushir~gstate history of LifeCycleTest servlet . " ) for (int i = 0;' i < states.size1); itt) { system.out.println(states.elemer~tAt(i).toString());

private String createState(String message) { return " 1 " t ( n e w java.util.Date0) .tostring() + " 1

" + message;

I I
Crear un archivoweb .xnd (descriptor de despliegue) en%BOOK-HOMER \ChO 6 \ f r e a k S e r v l e t \ W E B INF\ con ]as siguientes d e f i n i c i o n e s < s e r v l e t > y < e r r o r - p a g e > :

< ! DOCTY FE

Web-app FUBLIC "-//Sun Microsystems, Inc. //DTD Web Application 2. 3//ENn "http://java.sun.com/j2ee/dtds/Web-app 2 3 . d t d W >

Ahoracompileelservleteneldirectorio%~00~~~0~~%~h06\freak~erv1et\~~~-1~~\c1

Consulte el capitulo anterior para mas instrucciones.

<p>FreakServlet is temporarily unavailable. Please try <a href="/lifeCycle/servlet/freak">agair~</a>.</p> </body> </html>

Ahora necesitamos crear nuestro archivo WAR para el despliegue en la Implementaci6n de Referencia J2EE (cubriremos el asistente de apkaci6n Web mas adelante en el capitulo pero, por ahora, s610 desplegaremos nuestro servlet del mod0 mas ficil posible). Asegurese de que tiene 10s siguientes archivos en las siguientes posiciones:
/ u n a v a i l a b l e . htrnl /WEB-II.IF/ Web. xml classes/ FreakServlet.class

Cree ahora un archivo WAR utilizando el comando jar:


j a r -cf FreakServlet. war unavailable. htrnl WEB-INF

Ahora estamos preparados para desplegar el archivo WAR. Inicie el servidor de la Implementaci6n de Referencia J2EE ejecutando el archivo j 2 e e . b a t en el directorio % J2EE_HOME%\ b i n , ejecute luego el archivo d e p l o y t o o l . b a t en el mismo directorio, para iniciar la herramienta de despliegue. Cuando se e cargue la herramienta de despliegue, Cree una nueva aplicaci6n llamada fr e a k ~ e r v l t:

nppllcallon Dlsplay Name:

I -

Aiiada despuis nuestro archivo WAR a la nueva aplicacidn utilizando la o p c i 6 n ~ d dt o A p p l i c a t i o n (Agregar a la aplicacibn) del menu F i 1 e (Archivo):

Programacion de servlets

w
AS."

Egi -

FreakSefWet.war META-INFMANIFEST MF

META.tNF/aopllCalion xml METhlNFlsun-llee-rl xml

I mI
Descrlp(lon..

icons

...
-

Seleccione el archivo W A R en el cuadro de diilogo abierto para cargar el archivo W A R en la aplicaci6n. Ahora podelnos sencilla~nente desplegar nuestra aplicaci6n eligiendo D e p l o y (Desplegar) del men6 Tools (Herramientas):

[3 unavailable h h l

Capitulo 6
N o es necesario que hagarnos nada en la prirncra pantalla except0 volver a cornprobar si estamos desplegando la aplicacion correcta:

Please sebs c l the object to bs deployed and the s e m r to which t4 should be depbed:

The seruer can send back a client JAR I RMllllOP stub classes that client q l k application will need at runtime.
I ,

u cnem n ~ar

I,

sme owem nerwe oepmymg

En la siguientc pantalla, nccesitamos proporcionar el context0 que utilizarernos para navegar nuestra ~ p l i c ~ c i 6Configurelo n. cn 1 l f e c y c l e :

Programacion de servlets
Proceda hasta la pantalla final y seleccione F i n i s h para desplegar la aplicacion en el servidor:

Jr>-qr~--,.;

Conlacted Sew Application freak freaksewlet has Deploying Ejbs. Processing bea Making client JA M C Web Componenls Deployed. Deployment ofReakSetvlei is complete.

Ahora ya estl preparado para probar este servlet. Introduzca http:~localhost:8000/lifeCycle/se1vlet/freak para cargar el servlet. Vuelva a cargar el URL algunas veces utilizando el b o t h Actualizar de su navegndor. Hay dos tipos de respuestas que puede ver en el navegador. Veri la lista de estados en el ciclo sigue: de vida d e l ~ r e a k s e r v l e tcorno ,

F:eload
[Tue Jul 10 11:1?04 CMT+01:00 20011 Instantiation

/II l

[Tue Jul10 11:li.M GMT+O1.00 20011 h h b t i o n [Tue Jul 10 I I 1905 GMTf0l:OO 20011 Sentire
[Tue Jul 10 1l : l W 5 GMT+01:00 20011 Semce

[Tue Jul 10 11 19 33 GMT+Ol.OO 20011 Serv~ce

o veri la respuestn cuando el servlet introduzcn el estado n o disponible:

FI cakSeNiet is ternporanly unavjlfabtc Please try 2 1 1

En ambos casos, haga clic en el vinculo Actualizar en el navegador para invocar este servlet varias veces. Venios ahora corno son generados estos mensajes.

Instanciacion
Este estado corresponde a la construcci6n de la instancia del servlet por el contenedor. Remitase al constructorde~reak~e~vlet:

Este constructor inicializn un vector y un generador de nGmeros aleatorios. En este ejercicio, el vector st a t e s es utilizado para almacenar 10s estados conformen se van sucediendo. Cada estado es representado como unn cadena precedida por una cadena de fecha. El generador de n h n e r o s aleatorios es utilizado para lanzar de forma a~eatoria~navailable~xceptiondesdee~m~tododo~et 0.

Inicializacion
Este es el segundo estado e n cualquier servlet. Rernitase a1 m e t o d o init ( ) del F r e a k s e r v l e t :

314

Programacion de servlets
p u b l i c void i n i t ( ) throws ServletException ( s t a t e s . a d d ( c r e a t e s t a t e ( " I r ~ i t i a l i z a t i o r )~) " ; String waitIntervalString = g e t S e r v l e t C o n f i g ( ) . g e t I n i t P a r a m e t e r ( " w a i t I r 1 t e r v a 1 " ); i f (waitIntervalString != n u l l ) 1 w a i t I n t e r v a 1 = new I n t e g e r ( w a i t I n t e r v a l S t r i r ~ g )i n t v a l u e

( ) ;

I
Este mCtodo afiade otro estado llamado " I n i t i a l i z a t i o n " a1 historial de estados. Tambien extrae un parimetro " w a i t I n t e r v a l " de la configuraci6n del servlet. El F r e a k S e r v l e t utiliza este numero a1 lanzar la e x c e p c i 6 n u n a v a i l a b l e E x c e p t i on. Recuerde que especificamos un parimetro de inicializacion ( < i n i t - p a r a m > ) en el descriptordedespliegue:

Esto especifica un parimetro de inicializaci6n con nombre " w a i t I n t e r v a l " con valor " 5 ". Cuando el contenedor Web carga una aplicacion Web, tambien carga 10s parimetros de inicializaci6n asociados a la aplicacion. Al cargar la aplicacion, el contenedor crea un objeto s e r v l e t c o n f i g para cada servlet de la apkaci6n. Puede obtener este o b j e t o ~ e r v l e t ~ o n f mediante ig el metodo g e t s e r v l e t c o n f i g ( ) y extraer 10s parimetros de inicializaci6n. El metodo g e t ~ n i t ~ a r a m e t (e ) r puede devolver un valor n u l l si el parimetro solicitado no se encuentra en el descriptor de despliegue. Observe tambien que s61o 10s parimetros de cadena estin permitidos en el descriptor de despliegue. En el caso de F r e a k S e r v l e t , como nos interesaba un interval0 de tiempo de nGmero entero, debemos convertir programiticamante la cadena extraida " 5 " en un i n t . Fijese en que 10s dos estados anteriores solo tienen lugar durante la vida de una instancia de servlet.

Servicio
~ s t es e el tercer estado en el ciclo de vida del servlet. Remitase a la implementaci6n del metodo d o G e t ( ) Este metodo genera un Boolean aleatorio y, si el Boolean es t r u e , lanza una excepci6n U n a v a i l a b l e E x c e p t i o n , indicando que este servlet no estari disponible para procesar solicitudes en 10s pr6ximos segundos w a i t I n t e r v a 1 :
if (random.rlextBoolean ( ) ) { / / No d i s p o n i b l e d u r a n t e w a i t I r j t e r v a 1 s e g u n d o s s t a t e s . a d d ( c r e a t e s t a t e ( " U r ~ a v a i l a b l efrom d o G e t " ) ) ; t h r o w new U n a v a i l a b l e E x c e p t i o r ~ ( " ~ J r ~ a v a i l a b l from e doGet",
1

waitIr~terval;

Antes de lanzar la excepcih, el servlet afiade un estado llamado " U n a v a i l a b l e f o r m d o G e t ". En este caso, la informaci6n presentada en el navegador le informari de que el servlet no estaba disponible. Esta pigina muestra un pigina de error indicando que el F r e a k S e r v l e t no esti disponible. tC6mo se presenta esta pigina? Unavez el contenedor recibe l a ~ n a v a i l a b l e ~ x c e ~ t(o io cualquier n excepci6n mencionada en el apartado t h r o w s del mktodo s e r v i c e ( ) ), el contenedor verifica si se especifica una pigina de error en el descriptor de despliegue para esa excepci6n. En el caso del F r e a k s e r l v e t , el descriptor de despliegue tiene la entrada:

Esto especifica In ubicacidn de In pigina de crror para UnavailablcException. Al encontrar esta informaci6n de representacidn, el contenedor muestra la pigina de error siempre que se lanza esta excepci6n. Puede ampliar este rnecanisrno para mostrar niensajes agradables e n el caso de otras cxcepcioneb. Si n o especifica las piginas de error y su servlet lanza una excepcidn, dependiendo d e la implementacidn del contenedor, puede recibir mensajes n o tan agradables. En el caso d e Tomcat (el motor d e sendet que e s t i d e t r i s de la Implementacidn d e referencia JZEE), verh una traza de pila apuntado a la fuente de la cscepcidn. Aqui tiene una muestra de traza de pila:

Error: 500
Location: /lifeC'ycle/servlet/frei~k

i:i *I. t-~i:lrr~rr,:~ a l = a t t ? r i o generamlo e s f a l s e , F 1 - e a k Y e r v l e t qerbern u n a p > g i n a m<:,str,3njo 19s ? s t - a d o s registr-a.3,1~ h a s t a el rnornentc,. U t i l i z a rn6t8r~.jas d e 12 i r ~ t f r f a x H t t F < . S e r v l c f R e , ? u e a t p a r a f i j . 3 r e l tip:, ,de c o r r t e n i i o d ? L l a r e s p ' u e s t a 7 g e n e r 3 r e l HTML:

o u t .println [ " F r ~ a k S ~ r v l e t S : tate o u t .println("</title></head>"); c~ut.println("<bady>"):

History" ;

Programacion de servlets
o u t . p r l n t l n ( " < h l / F r e ~ k S e r v l e t : State History</hl/");

for (int 1 = 0; i < states.size(i; ltt) { out .prir~tlr, ( " < p > " t states. elernerjtAt ( i ) t "</p>") ;

Hay cuatro pasos a dar para generar la respuesta:


0

El primer paso es configurar el tip0 de contenido para la respuesta. La aplicaci6n receptora (el navegador) utiliza esta informacidn para saber c6mo tratar 10s datos de respuesta. En este caso, puesto que estamos generando salida HTML, el tip0 de contenido se configura en " t e x t / h t m l W . El segundo paso es obtener un objeto P r i n t w r i t e r de la respuesta. P r i n t w r i t e r es una clase del paquete java.io que amplia la clase abstracta j a v a . i o . W r i t e r . En el caso de 10s servlets, el contenedor construye el objeto P r i n t w r i t e r apartir del objeto j a v a . i o o u t p u t s t r e a m asociado a la conexidn de red subyacente del cliente. Con las implementaciones de base TCP/IP, del 10s contenedores obtienen normalmente un objeto j a v a . i o .~ u t ~ u t ~ t r e a mrecepticulo, utilizan ese objeto para crear el objeto P r i n t w r i t e r y lo asocian a1 objeto H t t p S e r v l e t R e s p o n s e . C o m o resultado, desde el interior del servlet, podri escribir la corriente de salida con la asociaci6n de red. Fijese en las etiquetas m e t a en el HTML generado. Estas etiquetas indican a1 navegador que n o debe memorizar esta pigina. Encontrari una etiqueta similar en u n a v a i l a b l e . h t m l . Sin estas etiquetas, veri que su navegador no recarga la pigina cuando hace clic en el v i n c u l o ~ c t u a l i z a r . La clase P r i n t w r i t e r tiene varios metodos para imprimir diversos tipos de datos en la corriente asociada. En este caso, utilizamos el mitodo p r i n t l n ( ) con un argument0 java. 1ang.String.

Finalmente, recuerde cerrar el objeto P r i n t w r i t e r a1 final.

Destruir
~ s t es a la etapa final del ciclo de vida del servlet. En el caso de F r e a k S e r v l e t , el metodo d e s t r o y ( ) es invocado antes de cerrar el servidor, sobre el que el contenedor Web asegura que las respuestas son descartadas adecuadamente. El ~ r e kas e r v l e t tiene una sencilla implementaci6n para este estado:
public \:aid d e s t r o y 0 { states. add (<-reatestate ("Destroy")) ; System. out .println ( " F l ~ ~ ~ s h istate r~g histbl-y of LifeCycleTest for (irjt i = 0; i ' states.size(); itt) { System.out.pri~~tlr~(states.elementAt ( i ). t o s t r i n g ( )) ;

servlet. " ) ;

Este metodo afiade un estado llamado " D e s t r o y " al vector s t a t e s e imprime la historia completa de estados en la ventana del servidor.

Capitulo 6
Finalmente, es conveniente tener presentes un par de puntos sobre el uso de varios mCtodos/objetos del API Servlet durante el ciclo de vida:

o Los objetos de clases tales c o m o s e r v l e t c o n f i g , s e r v l e t c o n t e x t ,


H t t p S e r v l e t R e q u e s t y HttpServletResponse son vilidos Gnicamente entre las invocaciones a 10s mktodos i n i t ( ) y d e s t r o y ( ) . Es decir, n o debe utilizar estos objetos antes de que sea invocado i n i t ( ) o despuks de invocar d e s t r o y ( ) . Por ejemplo, su constructor n o debe utilizar el m i t o d o l o g ( ) ,porque el mktodo l o g ( ) es implementado por el objeto ~ e r v l e t ~ o n t easociado xt a su servlet. Su instancia de servlet n o tendri una referencia vilida a1 objeto s e r v l e t c o n t e x t antes de i n v o c a r i n i t ( ) .
0

Fijese tambikn en el vector que estamos utilizando como variable de instancia en el F r e a k s e r v l e t . Puesto que kste no es un servlet S i n g l e T h r e a d M o d e l , el contenedor crea s610 una instancia de este servlet y dirige todas las solicitudes en hilos de ejecuci6n concurrentes a1 mCtodo d o G e t ( ) . Como este vector es una variable de instancia, las operaciones de lectura y escritura deberian estar a salvo de hilos. En el caso de la clase j a v a u t il . V e c t o r , 10s mCtodos a d d ( ) y s i z e ( ) estin sincronizados. Por esta raz6n, mGltiples usuarios de F r e a k s e r v l e t pueden interactuar con su ciclo de vida y todavia ver la historia de estados mis actualizada.

Aqui termina nuestro anilisis sobre el ciclo de vida de 10s servlets.

Solicitudes y respuestas
Lasinterfacesjavax. s e r v l e t . H t t p S e r v l e t R e q u e s t y j a v a x . s e r v l e t . H t t p S e r v l e t R e s p o n s e son las clases de las que dependen 10s servlets para acceder a las solicitudes y respuestas HTI'P. Como se muestra en el diagrama de clase UML a1 principio de este capitulo, ksta es la lista completa de interfaces y clases para tratar solicitudes y respuestas:

En esta lista, 10s elementos en cursiva son interfaces, mientras que el resto son clases abstractas o concretas. Las interfaces H t t p S e r v l e t R e q u e s t y H t t p S e r v l e t R e s p o n s e son versiones m i s especializadas de las interfaces s e r v l e t R e q u e s t y S e r v l e t R e s p o n s e para el HTTP. Las dos clases pueden ser utilizadas para leer desde y escribir en corrientes de entrada y salida respectivamente. Las clases con nombres terminados en W r a p p e r con clases concretas de las correspondientes interfaces.

Programacion de servlets

La interfaz ServletRequest
public interface ServletRequest

Esta interfaz especifica una abstraccion de solicitudes de cliente para un servlet. El contenedor Web crea una instancia de este objeto mientras invoca el metodo s e r v i c e ( ) de G e n e r i c S e r l v e t o H t t p S e r v l e t . Como referencia, esta es la lista completa de metodos de esta interfaz:
public public public public public public public public public public public public public public public public public public public public public public public public Object getAttribute(String name) void setAttribute (String name, Object attribute) Enumeration getAttributeNames ( ) void removeAttribute (String name) Locale getlocale 0 Enumeration getLocales() String getCharacterEncoding() void setCharacterEncoding(String env) int getcontentlength ( ) String getContentType) ServletInputStream getInputStream0 String getparameter (String name) Enumeration getParameterNames0 String [ 1 getparametervalues 0 Map getParameterMap ( ) String getprotocol ( ) String getscheme ( ) String getServerName ( ) int getserverport ( ) Buff eredReader getReader ( ) String getRemoteAddr0 String getRemoteHost ( ) boolean issecure 0 RequestDispatcher getRequestDispatcher(String path)

Puesto que esta interfaz tiene bastantes metodos, agrupemoslos basindonos en su uso y examinemos algunos de 10s mktodos mis comunmente requeridos.

Metodos para solicitar parametros


Los siguientes metodos pueden ser utilizados para acceder a 10s parametros de solicitud. En el caso de solicitudes HTTP, estos metodos pueden ser utilizados tanto para solicitudes GET como para solicitudes POST.

public String getparameter (String name)

Este metodo intentari localizar un parimetro con la clave proporcionada, name, en la solicitud y devolver su valor. Si hay multiples valores para el parimetro dado, entonces este metodo devuelve el primer valor de la lista. Este metodo devuelve n u l l si la clave no se encuentra en la solicitud.

public String[ I

getparametervalues (String key)

Si un parimetro puede devolver m~ltiples valores, como un conjunto de casillas de verification, una lista multi-selection o incluso mdtiples controles con el mismo nombre, este metodo devuelve una matriz que contiene 10s valores de parimetros.

Capitulo 6
El rnetodo getPararneterNarnes0
public Enumeration getParameterNames0

Este metodo devuelve una enumeracion de todos 10s nombres de parimetros para la solicitud. Si la solicitud no tiene parimetros, devuelve una enumeracion vacia.

El metodo getPararneterMap0
public Map getParameterMap0

Este metodo devuelve un j a v a u t i 1.Map que contiene todos 10s pardmetros de solicitud. En este mapa, el nombre del parametro es la clave, mientras que su valor es el valor del mapa. Tanto las claves como 10s valores son cadenas. Observe que este mapa es inmutable y puede cambiar 10s valores de este mapa.

Metodos para atributos de solicitud


Aparte de 10s parimetros de solicitud, 10s contenedores Web o sewlets/JSP pueden adjuntar atributos a las solicitudes. La especificaci6n del API Sewlet especifica tres enfoques diferentes para almacenar y recuperar atributos. U n o de ellos es adjuntar atributos a objetos solicitud. Los otros dos enfoques utilizan H t t p S e s s i on y S e r v l e t C o n t e x t (que analizaremos en el siguiente capitulo) para almacenar y recuperar atributos. Como veremos en posteriores capitulos, la especificaci6n JSP proporciona un mecanismo adicional utilizando P a g e c o n t e x t para almacenar y recuperar atributos. Cada uno de estos enfoques proporciona la nocidn de un alcance para que existan 10s atributos. En el caso de 10s atributos adjuntados a objetos solicitud, la vida de estos atributos es la de la misma solicitud. En el lenguaje de servlets, un atributo es un objeto de lenguaje Java nominado. Al configurar un atributo, asigne un nombre al atributo y, a1 recuperar el atributo, especifique el mismo nombre. Los nombres son objetos String. El proposito de 10s atributos en el alcance de la solicitud es permitir al contenedor o a otro servlet enviar datos adicionales a un servlet o JSP. Para el desarrollador de aplicaciones, 10s atributos son muy utiles a1 utilizar el objeto RequestDispatcher para enviar solicitudes desde un servlet a otro. Los siguientes metodos pueden ser utilizados para gestionar atributos en el context0 de la solicitud.

El rnetodo getAttribute0
public Object getAttribute(String name)

Este metodo devuelve el valor del atributo nominado (o n u l l si el atributo nominado no existe)

El rnetodo getAttributesNarnes0
public Enumeration getAttributeNames0

Este m i t o d o devuelve una enumeracion de todos 10s atributos contenidos en la solicitud. Devuelve una enumeracion vacia si n o hay atributos en la solicitud.

El rnetodo setAttribute0
public void setAttribute(Strin9 name, Object attribute)

Este metodo configura un atributo nominado.

El rnetodo rernoveAttribute0
public void removeAttribute (String name)

Promamacion de servlets
Este metodo elimina el atributo nominado de la solicitud.

Metodos de entrada
Como hemos analizado anteriormente, el S e r v l e t R e q u e s t alberga una referencia a la conexi6n cliente subyacente. Utilizando 10s siguientes mktodos, puede aceder a la corriente y a 10s objetos de escritura asociados a la solicitud.

El metodo getlnputstreamo
public ServletInputStream getInputStream0 throws java.io.IOException

Este metodo puede utilizarse para acceder a1 cuerpo de la solicitud utilizando un objeto ServletInputStrearn

El metodo getReader0
public java.io.BufferedReader g e t R e a d e r 0 throws java.io.IOException

Este metodo puede utilizarse para acceder a1 cuerpo de la solicitud utilizando un objeto lector de bufer.

El metodo getCharacterEncoding0
public String getCharacterEncoding0

Este metodo devuelve el nombre de la codification de caracteres utilizada en el cuerpo de la solicitud.

El metodo setCharacterEncoding0
public void setCharacterEncoding(String env)

Este metodo puede utilizarse para ignorar el nombre de la codificaci6n de caracteres utilizada en el cuerpo de la solicitud. Este metodo debe ser invocado antes de acceder a 10s parimetros desde la solicitud o antes r ~ n p u t ~ t r e a m la d solicitud. e de obtener e l ~ e a d e o

La clase ServletRequestWrapper
public class ServletRequestWrapper implements ServletRequest

Esta clase proporciona una conveniente implementaci6n de la interfaz j a v a x . s e r v l e t . S e r v l e t R e q u e s t . Excepto un constructor, esta clase nointroduce ningun metodo nuevo. El anilisis de la funcidn de estas clases envoltorio esti reservado para posteriores secciones de este capitulo.

La interfaz HttpServletRequest
public interface HttpServletRequest extends ServletRequest

Los metodos mis comunmente utilizados en esta interfaz son 10s metodos para acceder a 10s parimetros de solicitud. Para comprender c6mo utilizar estos metodos, consideremos cdmo HTTP permite que 10s datos sean pasados a1 servidor Web. Como hemos visto en el capitdo anterior, HTTP le permite enviar parimetros junto con una solicitud. En una solicitud GET, estos parimetros son adjuntados a la URL de

solicitud en forma de cadena de solicitud mientras que, en una solicitud POST, 10s parimetros son enviados en el cuerpo de la solicitud en formato x-www-f o r m - u r l e n c o d e d . En cualquier caso, estos parimetros son presentados como pares de valores clave. HTTP no requiere que las claves sean unicas, por lo que, para algunas claves, puede haber una lista de valores. Los ejemplos incluyen multiples listas de seleccidn o grupos de casillas de verificacidn. Cuando construya una hoja HTML para solicitudes GET o POST, especifique ciertos controles utilizando las etiquetas < i n p u t > . Cada control tiene un t y p e (tipo), como c h e c k b o x (casilla), t e x t (texto) o s u b m i t (enviar), y t a m b i h puede tener un name (nombre) y/o v a l u e (valor). El atributo name define la clave por la que sera conocido el valor devuelto a1 servidor. El atributo v a l u e tiene diferentes efectos sobre diferentes controles. Obviamente, si damos a mis de una etiqueta < i n p u t > el mismo nombre, podemos tener varios pares de claves/valores con la misma clave como parte de nuestra solicitud. La siguiente tabla muestra 10s valores enviados a1 servidor para diferentes tipos de controles de forma. Tipo de control text Descripci6n Valor devuelto

Cam o de entrada de texto de una Texto introducido por el usuario o sola inea, con atributo value como el texto por defecto contenido por defecto Texto introducido por el usuario o Area de texto de multiples lineas, con atributo value como contenido el texto por defecto por defecto Campo de entrada de contraseiia de Texto introducido por el usuario una sola linea (muestra :"en lugar del caricter introducido) Casilla de verificacion estindar Siesti marcada: atributovalue (o "onVsi no esti es ecificada) Si n o esti marcada: no devueRe par de valores clave Atributo v a l u e solo de b o t h radio seleccionado

textarea

password

checkbox

radio

B o t h radio estindar. Todos 10s botones con el mismo name forman un grupo de botones, de mod0 quesolo uno pueda se seleccionado

select

Elementos seleccionados por el usuario Utilizado para crear una lista de elementos desde la que el usuario o elemento(s) por defecto puede seleccionar; puede de un solo valor o de multiples valores Boton enviar, con atributo value como leyenda de b o t h Ninguno, a menos que el atributo name facil~tado. El contenido d e v a l u e por defectoes " S u b m i t "

submit

hidden

Campo de forma que no es visible A t r i b u t o v a l u e en el navegador y por ello no puede ser modificado por el usuario

Existen otros controles per0 kstos son suficientes por ahora. La raz6n mis comun para tener multiples controles con el mismo name es poder construir grupos de botones de opci6n y casillas de verificacion, y controles s e l e c t de multiples selecci6n. El grupo de botones de opcidn devolverh el 6nico v a l u e seleccionado y 10s controles s e l e c t de casillas de verificacidn o de multiple selecci6n devolverin todos 10s v a l u e s seleccionados.

Programacion de servlets
Cualquier objeto que implemente la i n t e r f a z ~ t t pe s r v l e t R e q u e s t (como el objeto solicitud H'ITP pasado desde el contenedor Web) proporcionari acceso a todos 10s datos de la solicitud a travks de sus metodos. Observe que, puesto que la i n t e r f a z H t t p s e r v l e t R e q u e s t e s t i destinada a encapsular H'ITP, esta interfaz (en combinacibn con 10s mktodos proporcionados en la interfaz S e r v l e t ~ e q u e s t ofrece ) numerosos mktodos para acceder a la solicitud HTTP:
public public public public public publ ic public public public public public public publ i c public public public public public public publ i c public public public public String getAuthType 0 Cookie [ I getcookies ( ) long getDateHeader (String name) String getHeader (String name) Enumeration getHeaders (String name) Enumeration getHeaderNames0 int getIntHeader (String name) String getMethod0 String getcontextpath ( ) String getPathInfo ( ) String getPathTranslated0 String getQueryString ( ) String getRemoteUser ( ) boolean isUserInRole(String role) getuserprincipal ( ) String getRequestedSessionId() boolean isRequestedSessionIdValid() boolean isRequestedSessionIdFromCookie() boolean isRequestedSessionIdFromURL~) String getRequestUR1 StringBuffer getRequestURL String getServletPath ( ) HttpSession getsession0 Httpsession getsession (boolean create)

Los siguientes son algunos de 10s metodos mis comGnmente utilizados especificados en la interfaz H t t p S e r v l e t R e q u e s t . Encontrari algunos de 10s metodos restantes en el siguiente capitulo.

Metodos para solicitar ruta y URL


El primer grupo de metodos permite a un servlet obtener el URL y la ruta de solicitud con la que ha sido invocado.

El metodo getpathlnfoo
public String getPathInfo0

Este metodo devuelve cualquier informaci6n extra de ruta con el URL solicitud. En general, se invoca un servlet utilizando su alias o el nombre de clase. Por ejemplo, puede acceder a un s e r v l e t ~ e yr ~v l e t u t i l i z a n d o e l U R L h t t p : / / h o s t : p o r t / m y A p p / M y S e r v l e t , d o n d e ~ y ~ p pelcontextode es aplicacibn. Sin embargo, puede enviar informaci6n adicional de ruta a1 servlet, por ejemplo como h t t p : / /<HOST> : <PORT>/myApp/MyServlet/wrox. En este caso, / w r o x es la inforrnacibn adicional de ruta. El servlet puede utilizar el metodo g e t P a t h I n f o ( ) para obteneresta ruta. Este rniitodo devuelve n u l l si n o existe ruta adicional en la solicitud.

El metodo getPathTranslated0
public String getPathTranslated0

Este metodo traduce la informacibn extra de ruta en una ruta real. Por ejemplo, en el ejemplo anterior, si la c l a s e ~ y ~ e r v lees t i situada en el directorioc: \work\MyApp\WEB-INF\, este metodo devuelve c : \work\MyApp\wrox como la ruta traducida.

Capitulo 6
Este m t t o d o devuelve null si n o hay ninguna ruta adicional en la solicitud.

El metodo getQueryString0
public String getQueryString0

Este m t t o d o devuelve la cadena de consulta asociada a la solicitud.

public

String getRequestURI0

Este metodo devuelve la ruta URI asociada a la solicitud. En el ejemplo anterior, este mitodo devolveria / MyApp/MyServlet/wrox.

El metodo getRequestURL0
public StringBuffer getRequestURL0

Este m i t o d o reconstruye el URLque el cliente ha utilizado para realizar esta solicitud. La cadena devuelta incluye el protocolo, el nombre del servidor y la ruta del servidor para esta solicitud.

El metodo getsewletpatho
public String getServletPath ( )

Este mitodo devuelve la ruta URI asociada con el servlet. ~ s t excluye e cualquier informaci6n extra de ruta y cualquier cadena de consulta. Por ejemplo, en el caso anterior, este mitodo devolveria /MyApp/ MyServlet y la ruta de servlet.

Metodos para cabeceras H l l P


El siguiente grupo de mitodos permite a 10s servlets leer cabeceras H T T P enviadas con la solicitud.

public

String getHeader(String name)

Este metodo devuelve el valor de la cabecera nominada de la solicitud HTTP. Este mitodo devuelve null si la solicitud n o incluye la cabecera especificada.

El metodo getHeaders0
public Enumeration getHeaders (String name)

Este metodo devuelve una enumeraci6n de todos 10s valores de cabecera de la solicitud.

El metodo getHeaderNames0
public Enumeration getHeaderNames.0

Este mttodo devuelve una e n u m e r a c i h de nombres de cabecera de solicitud.

El metodo getMethod0
public String getMethod()

Proeramacion de servlets
Este m t t o d o devuelve el tipo de la solicitud HTTP, como GET, POST, etc. Aparte de estos mitodos, existen diversos mttodos especificos para sesiones HTTP. Examinaremos algunos de estos mitodos en el pr6ximo capitulo.

La clase HttpServletRequestWrapper
public class HttpServletRequestWrapper implements HttpServletRequest

La clase proporciona una implementaci6n conveniente de la interfaz

j a v a x .s e r v l e t .h t t p .H t t p S e r v l e t R e q u e s t y, exceptoun constructor, no introduce ninglin mttodo a funcion de estas clases envoltorio es analizada exhaustivamente mis adelante en este capitulo. nuevo. L

La interfaz ServletResponse
public interface ServletResponse

~ s t es a el equivalente de respuesta del objeto S e r v l e t R e s q u e s t abstrae la mayoria de 10s mttodos necesarios para construir respuestas para servlets. Esta interfaz especifica 10s siguientes mttodos:
public public pub1 i c public public public public public public public public public public String getCharacterEncoding() ServletOutputStream getOutputStream0 Printwriter getwriter ( ) void setContentLength(int length) void setContentType (String type) void setBufferSize (int size) int getBufferSize ( ) void reset() boolean isCommitted() void f lushBuf f er ( ) void resetBuf f er ( ) void setlocale ( ) Locale getlocale ( )

Los siguientes son algunos de 10s mttodos mis comunmente utilizados de esta interfaz.

Metodos para tip0 de contenido y longitud


Estos mktodos permiten a1 servlet configurar el tip0 de contenido MIME y la longitud de contenido de la respuesta.

public void setContentType(String type)

Este metodo establece el tip0 de contenido de la respuesta. Si e s t i utilizando el objeto P r i n t w r i t e r (que examinaremos en breve) para generar la respuesta, antes de escribir la respuesta, debe invocar s e t C o n t e n t T y p e ( ) para configurar el tipo MIME de la respuesta HTTP. En el caso de HTML, el tipo MIME debe ser fijado e n " text/HTMLT'.

public void setcontentlength (int size)

Este metodo puede utilizarse para establecer la cabecera de longitud de contenido del contenido.

Metodos de salida
Los siguientes metodos son utiles para generar contenido de texto o binario en la respuesta.

El metodo getOutputStream0
public ServletOutputStream getOutputStream() throws java.io.IOException

Este metodo devuelve un objeto s e r v l e t ~ u t p u t ~ t r e a m q puede ue ser utilizado para escribir datos binarios en la respuesta. Esta clase s e r v l e t o u t p u t s t r e a m es una subclase de j a v a . i o o u t p u t s t r e a m E n u n o b j e t o ~ t t p ~ e r v l e t ~ e s p o dado, n s e debe invocareste metodo s61o una vez. Si intenta invocar este metodo mis de una vez, encontrari una excepci6n IllegalStateException.

El metodo getwriter0
public java.io.PrintWriter getwriter0 throws java.io.IOException

Este metodo devuelve un objeto p r i n t w r i t e r que pueda ser utilizada para enviar textos de caracteres en una respuesta. El objeto P r i n t w r i t e r traduce automiticamente 10s caracteres Unicode internos de Java en la correcta codificaci6n de mod0 que puedan ser leidos en la miquina cliente. C o n el objeto P r i n t w r i t e r , normalmente escribiri datos en el objeto respuesta utilizando su m i t o d o p r i n t l n ( S t r i n g s t r i n g ) . Similaral m 6 t o d o g e t ~ u t p u t s t r e a m ( ) ,este metodo tampocodeberia ser invocado m i s de unavez en un o b j e t o H t t p s e r v l e t R e s p o n s e dado. Ademis, s61o uno de 10s dos mktodos anteriores debe ser invocado en cualquier objeto HttpServletResponse.

Metodos para salida en bufer


TambiCn puede enviar respuestas en bhfer desde sus servlets. Los siguientes mktodos son Gtiles para controlar el almacenamiento en biifer. Si esti enviando una gran cantidad de datos en la respuesta, debe considerar configurar el tamafio del bufer en valores mis pequefios, de mod0 que el usuario puede empezar a recibir datos ripidamente.

El almacenamiento en bGfer tambiCn le permite abortar el contenido generado hasta el momento y


reiniciar la generaci6n.

El metodo setBufferSizeO
public void setBufferSize (int size)

Este mktodo establece el tamafio de bufer preferido para el cuerpo de la respuesta. Observe que el contenedor Web utilizari un bufer como minimo del mismo tamafio requerido.

El metsdo getBufferSize0
public int getBufferSize 0

Este metodo devuelve el tamafio real del bufer utilizado para la respuesta.

El metodo resetsuffer0
public void resetBuf fer 0

Programacion de servlets
Este mitodo elirnina el contenido del bGfer subyacente sin elirninar las cabeceras de respuesta o el c6digo de estado. Si la respuesta ya ha sido realizada, este mitodo lanzauna excepci6n ~ l l e g a l ~ t a t e ~ x c e p t i o n .
El metodo flushBuffer0
public void flushBuffer 0 throws java. io. IOException

Este rnitodo fuerza cualquier contenido del bufer a ser escrito a1 cliente.
El metodo iscommitted0
public boolean i s c o m m i t t e d 0

Este metodo devuelve una booleana indicando si la respuesta del bGfer ha sido realizada.
El metodo reset0
public void reset 0

Este metodo es Gtil para reiniciar el bGfer desechando con ello el contenido del bufer.

La clase ServletResponseWrapper
public class ServletResponseWrapper implements ServletResponse

La clase proporciona una irnplernentaci6n conveniente de la interfaz j avax . s ervlet . ServletRespons e. Excepto un constructor, esta clase no introduce ningGn metodo nuevo. Verernos rnuy pronto la funcion de estas clases envoltorio.

La interfaz HttpServletResponse
public interface HttpServletResponse extends ServletResponse

El contenedor Web proporciona un objeto que irnplernenta esta interfaz y la pasa a1 sewlet rnediante el metodo service ( ) . El sewlet puede rnodificar las cabeceras de la respuesta y devuelve resultados a traves Esta s e .interfaz incluye 10s siguientes rnitodos: del o b j e t o ~ t t p ~ e r v l e t ~ e s p o n
public public public public public public public public public public public public public public void addcookie (Cookie cookie) boolean containsHeader(String headerName) String encodeURL(String url) String encodeRedirecURL(String url) void sendError (int status) void sendError (int status, String message) void sendRedirect(String location) void setDateHeader(Strin9 headerName, long date) void setHeader(String headerName, String value) void addHeader (String headerName, String value) void addDateHeader(Strin9 headername, long date) void addIntHeader (String headerName, int value) void setIntHeader(Strin9 headerName, int value) void setstatus (int status)

Aparte de estos rnktodos, esta interfaz tarnbien especifica una serie de c6digos de error que corresponde a errores H T T P estindar. Rernitase a la docurnentaci6n API para encontrar esta h a .

Capitulo 6
Los siguientes son algunos de 10s metodos bisicos para escribir contenido en la respuesta.

Metodos para el manejo de errores


Este grupo de metodos permite a un servlet enviar un mensaje de error o configurar el c6digo de estado H'ITP.

El metodo sendError0
public void sendError (int status)

Los senlets pueden utilizar este metodo para indicar c6digos estindar de estado HTTP. Como hemos visto en el caso del F r e a k S e r v l e t , puede especificar piginas de error para diferentes errores HTTP y excepciones de senlet. Si existe una pigina correspondiente al c6digo de estado, el contenedor envia la pigina especificada a1 cliente. Si no hay una pigina especificada, el contenedor envia su pigina de error por defect0 indicando el c6digo de estado y un mensaje c ~ r r e s ~ o n d i e n t e .

El metodo sendError0
public void sendError (int status, String message)

Este mensaje es similar a1 metodo s e n d E r r o r ( s t a t u s ) ,except0 en que tambien acepta un mensaje de estado. Puede utilizar este mensaje para indicar fallos especificos.

El metodo setstatus0
public void setstatus (int status)

Este metodo puede utilizarse para enviar c6digos de estado H T T P que no Sean errores.

El metodo sendRedirect0
public void sendRedirect (String location)

Este metodo envia una respuesta desviada a1 cliente. El cliente recibe el codigo 302 de respuesta H T T P indicando que el cliente esti siendo desviado temporalmente a la posicion especificada. Si la posici6n especificada es relativa, este metodo la convierte en un URL absoluto antes de desviarla.

La clase HttpServletResponseWrapper
public class HttpServletResponseWrapper implements HttpServletResponse

La clase proporciona una implernentacion conveniente de la interfaz j a v a x . s e r v l e t .h t t p . HttpServletResponse.Exceptounconstructor,estac~asenointroduce ningfin metodo nuevo. A continuation, examinaremos detalladamente la funci6n de estas clases envoltorio.

Funcion de las clases envoltorio


Cuatro clases envoltorio son introducidas en la version 2.3 del API Senlet: javax.servlet.ServletRequestWrapper,javax.servlet.ServletResponseWrapper, javax.servlet.http.HttpServletRequestWrapper,y javax.servlet.http.HttpServletResponseWrapper.

Programacion de servlets

Todas estas clases aiiaden un constructor a 10s mktodos especificados en las interfaces que implementan. Los constructores son parecidos y requieren una implementacion de las interfaces que implementan. Por ejemp10,~aracrearunainstanciade ja v a x .s e r v l e t h t t p ~ t t p ~ e r v l e t ~ e q u e s t ~ r a p p e r , n e c e s i t a proporcionar otraimplementaci6n de lainterfaz j a v a x .s e r v l e t .h t t p .H t t p S e r v l e t R e q u e s t .

Internarnente, todos 10s mktodos de estas clases delegan su funcidn en la clase de irnplementacion pasada a travks del constructor. Corno puede ver, estas clases no afiaden ninguna funcionalidad extra. Entonces, icual es exactarnente su funcion? Sirnplifican la tarea de crear implernentaciones concretas de las interfaces solicitud/respuesta. Por ejernplo, considere una situaci6n en la que necesitarnos implernentar el metodo g e t p a r a m e t e r ( ) de la interfaz j a v a x . s e r v l e t .h t t p . H t t p S e r v l e t R e q u e s t . En lugar de irnplementar todos 10s rnetodos de esta interfaz, podernos utilizar la clase envoltorio como se rnuestra en el siguiente fragment0 de c6digo:
public class MyRequest extends HttpServletRequestWrapper
{

p'ublic MyReyuest (HttpServletRequest request) { super(request); / / Cualquier otra ir~icializaciin 1 public String getparameter (String rlame) [ / / Su implementaci6n aylui

I
I

Los rnetodos restantes de esta clase sirnplernente delegan su irnplementaci6n en el objeto solicitud pasado durante la construccion. De este rnodo, podemos rnodificar el cornportarniento de algunos o de todos 10s mktodos de 10s objetos solicitud y respuesta que proporciona el contenedor. Sin embargo, id6nde y c6mo crearnos instancias de estas clases? Observe que, para instanciar estas clases, necesitarnos primer0 una irnplernentaci6n concreta. Existen a1 rnenos dos situaciones en las que se nos ofrece una oportunidad de carnbiar 10s objetos de solicitud y de respuesta:
O

El API RequestDispatcher Desde el interior de 10s semlets o de las piginas JSP, puede invocar rnktodos en la interfaz j a v a x . s e r v l e t .R e q u e s t D i s p a t c h e r . Aprenderernos rnis sobre este APIen elpr6ximo capitulo. Mientras invoca estos mktodos, necesitamos pasar explicitarnente 10s objetos solicitud y respuesta que son recibidos a travks de uno de 10s rnetodos ~ O X X X ( ) de nuestro semlet. Mientras asi lo hacernos, podernos crear objetos de solicitud y respuesta de adaptacih, y enviarlos en su lugar. El API filtro Existe una posibilidad similar con el API filtro. C o n el API filtro necesitamos invocar ( ) en el objeto F i l t e r c h a i n . Este metodo requiere objetos e ~ ~ l i c i t a r n e nel t er n k t o d o d o ~ i l t e r solicitud y respuesta. Tambien en este caso, podernos enviar objetos de solicitud y de respuesta de adaptacion en lugar de 10s objetos de solicitud y de respuesta que recibe el filtro.

En arnbos casos, podernos construir instancias de objetos de solicitud/respuesta pasando las instancias implementadas por el contenedor corno argurnentos.

Programacion de servlets Aplicacion de apoyo tecnico


Despuks de analizar el API Semlet y el ciclo de vida del semlet, considerernos ahora otra aplicaci6n que supone:

329

Capitulo 6
Recoger una solicitud de apoyo ticnico Esta parte de la aplicaci6n ilustra la obtenci6n de parimetros de solicitudes HTTP
0 Almacenar la solicitud de apoyo e n una base de datos

Esta parte de la aplicaci6n ilustra un enfoque a salvo de amenazas para generar n6mero de secuencia y almacenar datos en la base de datos

O Generar una pigina de confirmaci6n


Esta aplicaci6n requiere una base de datos para almacenar las solicitudes de apoyo tkcnico. En la configuraci6n actual, estamos utilizando la base de datos Cloudscape.

Cloudscape estd incluida en J2EE SDK 1.3. Tambie'n puede configurar una base de datos diferentes cambiando 10s pardmetros del descriptor de despliegue (descrito posteriormente).
Para este ejemplo, crearemos una aplicaci6n de solicitud de apoyo tkcnico para una compaiiia ficticia llamada Corporation XYZ. Para desarrollar esta aplicacion, haremos lo siguiente:

O Preparar una pigina HTML con un formulario para recabar la solicitud de apoyo tkcnico
0 Prepara las tablas de la base de datos, creando un esquema para dichas tablas

O Crear el senlet Techsupportservlet para procesar el formulario, insertar la solicitud en las tablas y generar una pigina de confirmaci6n

Configurar la pagina HTML


El proposito de esta pigina es proporcionar un formulario para presentar solicitudes de apoyo tkcnico. Encontrari que 10s controles utilizados pueden ser aplicados a numerosos otros formularios. El siguiente HTML contiene el formulario para recabar 10s datos de la solicitud de apoyo tkcnico:
<html> <head> <title>XYZ Corporation, I T Department</title> </head> <body> <hl>Technical Support Request</hl> <hr><br> <center> <form action="/techSupport/servlet/techSupport" method="POST"> <table align="center" width="100%" cellspacing="2" cellpadding:"2"> <tr> <td align="right">First Name:</TD> <td><input type="TextV' name="firstName" align="left" size="15"></td> <td aliqr~="right">Last Name: </TD> <td><input type="Textl' name="lastName" align="left" size="15"></td> </tr> <tr> <td align="right">Email:</td> <td><input type="Text" name="email" align="left" size="25"></td> <td align="right">Phone: </td> <td><input type="TextV name="phoneW align="leftW size="15"></td> </ tr > <tr> <td align="right">Software:</td> <td> <select name="software" size="lW> <option value="Word">Microsoft Word</option> <option value="Excel">Microsoft Excel</option>

<option value="Access">Micr@soft Access</optinn> <optinn value="Outlook">Micrasoft Outlool.:':/c~ticn> </select> </ t d > <td a l i q n = " r i g h t " > O p e r a t i n g S y s t e m : </ t d > <td> <select name="osW si:e="l"> <option value=" 95"rWindows 35</optian> <option value="98">Window.~ PQ</option> < o p t ion value="2KFro">Windows 2000 Fro</option> <option value="ZKServer">Windows 2000 Server</option> <option value="XP">Windows XP</option>

<br>Frnblem Description <br> itextarea name="problem"

c o l ~ = " 5 0 " rows="4"></textarea>

<input

type="Subrnlt"

name="suhmit"

v a lue="Submi t R e q u e s t ":,

</ form>
</center> .</body> p/html>

Asi es como quedaria:

Technical Support Request


Fmt Namc

Last Name

Problem Dncriphon A l

Capitulo 6
Preparar la base de datos
Antes de proceder a escribir el servlet, deberiarnos preparar las tablas de la base de datos almacenando las solicitudes de apoyo tkcnico. Utilice las herrarnientas de base de datos proporcionadas por el vendedor (corno CloudView para Cloudscape o SQL Plus para Oracle) para crear la base de datos. Utilizarernos Cloudscape ya que viene con la Irnplernentacidn de Referencia J2EE. Para trabajar con Cloudscape, utilizarnos una herrarnienta facilitada llarnada CloudView. Para iniciar CloudView, desde el directorio %J2EE-HOME% \l i b \ s ys temejecute:

Desde la ventana principal, seleccione F i l e I New D a t a b a s e y Cree una nueva base de datos en la carpetapordefecto de Cloudscape ( 2 J2EE_HOME% \ C l o u d s c a p e ) l l a r n a d a t e c h ~ u p p o r t :

Database

1s

Localization Enetyptio~

Name: ~~:\j2sdkeel.382\cloudscapeMechSupporl

DespuCs, con la nueva base de datos seleccionada en la vista de drbol, utilice el siguiente S Q L para crear la tabla para esta aplicacidn:
CREATE TABLE S U P P REQUESTS(REQUEST ID
FIRST NAME LAST N A M E EMAI L PHONE SOFTWARE 0s PROBLEM

INP CEFAIJLT FZJMINWDFNT INITIAL 1


INCREMENT 1 NOT NULL, VARCHAR ( 4 0 ) , VARCHAR(40), VARCHAR [ 4 0 ) , VARCHAR ( 1 5 ) , VARCHAR(401, VARCHARI40), LONG V A R C H A R ) ;

La primera columna esta' configurada en u t u columna AUTOINCREMENT, de tal modo que la base de datos incrementara' automa'ticamente la columna REQUEST-ID cuando se rste' creando una nueva solicitud.

Programacion de servlets

El esquerna para esta aplicacion tiene una tabla, una tabla SUPP-REQUESTS para ahacenar las solicitudes de apoyo tCcnico.

Escrlbir e l servlet
Puesto que el formulario de nuestra pigina HTML tiene una solicitud POST, necesitarnos irnplernentar un servlet con el mitodo d o ~ o s (t ) ignorado. Para procesar la solicitud de apoyo tecnico, hay varias tareas que este metodo debe realizar:

O Extraer la entrada del forrnulario de H t t p S e r v l e t R e q u e s t , utilizando 10s rnetodos getparameter ()

rn

Insertar 10s datos en una tabla de base de datos Leer desde el nuevo registro el I D que la base de datos ha autoincrernentado por nosotros

0 Generar una pigina de confirmaci6n para el usuario con un nGrnero de referencia El perfil de la c l a s e ~ e c h s u p p o r es t el siguiente:
/ / Importar p a q u e t e s de servlets i m p o r t javax.servlet.ServletConfig; import javax.servlet.Servl~tException; i m p o r t javax.servlet.1JnavailableException; i m p o r t javax.serv1et.http.HttpServIet; impnrt javax.serv1et.http.HttpServletRequest; i m p o r t javax.servlet.http.HttpServletRespunse;

//

I m p o r t a r o t r o s paquetes Java j a v a . io. P r i n t W r i ter; j ava. lo. I O E X c e p t P o r ~ ; java.sql.Connection; i m p n r t j a v a . sql. P r e p a r e d s t a t e m e r ~ t ; import l a v a . sql. R e c u l t s e t ; import j a v a . e q l .S@LEsceptim;
import import import

Capitulo 6
import j avax. sql DataSource; import j a v a x . n a m i n g . I n i t i a 1 C o n t e x t ; import j a v a x . n a m i n g . N a m i n g E x c e p t i o n ; public class TechSupportServlet extends HttpServlet

//

Los mktodos ir6n aqui..

1
Extraer datos del forrnulario
Para recabar 10s datos que el usuario ha introducido en el formulario, utilizamos el metodo getparameter (String key) del o b j e t o ~ t t ~ S e r v l e t ~ e q u El e sunicoargumentoparaeste t. metodo es un string que especifica el nombre del parametro que debe ser extraido. La siguiente instruccion del metodo dopost ( ) de este servlet extrae 10s parimetros del formulario de HttpServletRequest:
protected void d o P o s t ( H t t p S e r v 1 e t R e q u e s t req, HttpServletResponse res) throws ServletException, IOException [ String String String String String String String f i r s t ~ a m e = req.getParameter("firstName"); lastName = req.getParameter ("1astName") ; email = req.getParameter ("email"); phone = req.getParameter ("phone") ; software = req.getParameter ("software"); os = req.getParameter ("os") ; problem = req.getParameter ("problem") ;

Observe que leer parimetros de las solicitudes es sencillo. Si el parametro especificado se encuentra en la solicitud, el metodo get Parameter ( ) devuelve un objeto string valido. Sin embargo, si el formulario no contiene el parametro especificado, este metodo devuelve null. Fijese en que 10s drivers JDBC y las bases de datos esperan valores de campo legales (incluido no null) en las instrucciones SQL e instrucciones preparadas, y puede que tenga que comprobar tales condiciones antes de ejecutar instrucciones JDBC.

lnsertar la solicitud de apoyo tecnico


Despues de recabar 10s parimetros del formulario, el siguiente paso es ejecutar una instruccion SQL para insertar este dato:

int requestId = 0; Connection connection = null; String insertStatementStr = "INSERT INTO SUPP REQUESTS (FIRST NAME, LAST NAME, EMAIL, PHONE, " + "SOFTWARE, OS, PROBLEM) VALUES(?, ?, ? , ?, ?, ?, ?I"; try ( Initialcontext initialcontext = new Initialcontext(); DataSource datasource = (DataSource)initialContext.lookup((DataSourceiinitialContext.lookup("jdbc/'jd connection = dataSource.getConnection0; Preparedstatement insertstatement = connection.prepareStatement(insertStatemer~tStr); insertStatement.setString(1, insertStatement.setString(2, insertStatement.setString(3, insertStatement.setString(4, insertStatement.setString(5, insertStatement.setString(6, firstName); lastName); email); phone); software); 0s);

Programacion de servlets
insertStatemer~t. setstring ( 7 , problem) ; insertStatement.executeupdate ( ) ;
/ / Obterler el id de la solicitud autoir~crementado d e la base d e datos String selectStatementStr = "SELECT MAX(REQUEST ID) FROM SUPP REQUESTS";

Preparedstatement selectStatement = connection.prepareStatemer~t(selectstatementstr); Resultset resultset = selectStatement.executeQuery(); resultSet.next( ) ; / / Desplazarse hasta la primera d e resultados ; reqluestId = resultSet.getInt ( 1 )
}

fila en el grupo

catch throw catch throw

(NamingException ne) { n e w ServletException ("JNDI error", n e ) ; (SQLException sqle) { n e w ServletException ("Database error", s q l e ) ;

finally I if (connection ! = null) ( try I corlr~ectiorl. close ( ) ; 1 catch (SQLException sqle) { I

I
1

Este metodo utiliza j a v a . s q l .P r e p a r e d s t a t e m e n t para ejecutar la instrucci6n INSERT. Los pasos a seguir para insertar 10s datos en la tabla SUPP-REQUESTS son: Obtener una conexi6n de base de datos utilizando una bGsqueda JNDI para una fuente de datos

O Preparar una instrucci6n para INSERT O Configurar 10s parlmetros para la instrucci6n preparada O Ejecutar la instrucci6n preparada O Ejecutar otra instrucci6n para recuperar el r e q u e s t - i d O Cerrar la conexi6n de base de datos en el bloque f i n a l l y ; este paso tiene como objetim asegurar que la conexi6n siempre estl cerrada
Generar la respuesta

El Gltimo paso en T e c h s u p p o r t S e r v l e t es generar la respuesta para el usuario:


//

Preparar la respuesta Printwriter out = res.getWriter

( ) ;

res. setContentType ("text/htmll') ; out.println("<html><head><title>"); out .println ("Tech Support: Request Confirmation") ; out.println ("</title></head>") ; out .println ("<body>") ; out .println ("<hl>Tech Support: Request Confirmation</hl>" ) ; out.println("<p>Thank you for your request. Your request with the "following reference number has been received.</p>"); out .println ("<p>Request Reference: " + requestId + "</p>") ;

"

r.ut . p r i n t l n ( " i p : . ~ P l e a s en o t e t h i s number f o r f ~ ~ t u rr e f e r e r r s e s . < / p > " ; p u t .println{"<p>Yoiur request w i l l be attended to within 24 hours. < / p > ") ; o u t . p r i n t l n [ "<p>Administrator <br>Techsupport team. < / p > " I ; out.println["</body></html>");

Este paso completa el servlet.

Compilar la fuente
Compile 10s archivos de f u e n t e ~ e c h ~ u p p o r t ~ e r v .lj e ava t utilizando la siguiente linea de comando:

Construir la aplicacion Web


Arranque la herramienta de despliegue J2EE ejecutando el archivo d e p l o y t o o l . b a t localizado en el directorio: J 2 EE-HOME2 \ b i n . Cree una nuevaaplicacidn se~eccionando~ew>~pplication (Nuevo>Aplicacion) del menu F i l e (Archivo). Invoque la aplicaci6nTechSupport:

Seleccione entonces la aplicacion T e c h s u p p o r t en el irbol situado a mano izquierda y afiada un nuevo Web C o m p o n e n t (Componente Web) utilizando el men6 F i l e (Archivo). Pase la primera pantalla del New Web C o m p o n e n t Wizard (Asistente para nuevo componete Web) hasta Ilegar a la p a n t a ! l a ~ ~ ~ F i l e (Archivo War). Pulse el b o t h E d i t de modo que podamos aiiadir nuestro archivo de clase sendet y el archivo html al componente Web:

Programacion de servlets

h w ~ l n t ~FI!P~: le Q d c:\Wrox~ProJavaSeive~ChOtiltechSupport Q d src TechSupporlServlet.class TechSupportServtet.)aM Q WEB-INF

n
0

3onterltc: ofWph App


- -

Q UWEB-INF Q d classes
0-

0 TechSupporlSen4et.class

0 techsupp.html

d lib

Siga hasta la siguiente pmtalla del asistente y seleccione para desplegar s61o un servlet:

'3~ No Component
b
-.

-.

..

Capitulo 6
DespuCs vaya a la siguiente pantalla. Nombre a1 sewlet techsupport y elija nuestro archivo de clase
TechSupportServlet:

Please choose me JSP Ill0 or serhet class and provlde a name b r 11 Optlonalh! you can deflne Me relakve poshon In rhrch MIS component MU be loaded when me web appticatlon Is statled YOUcan also prowde a descnpbon and Icons for the rompanent

Sdltese las siguientes pantallas del asistente, aceptando las configuraciones por d e f e c t ~hasta , llegar a la pantalla Resource References (Referencias de recursos). Recuerde queen nuestro servlet obtenemos una conexi6n a la base de datos utilizando una fuente de datos. Por lo tanto, necesitamos informar a la aplicaci6n Web sobre la base de datos que vamos a utilizar, en este caso jdbc/TechSupport (configuraremos la fuente de datos en breve):

Please lisl any resource lactories rekencad In h e code orlhe cornponeMs I n thrs WAA file. For each be oilheae, indltate the b e ofresourcs rearnred, and h m f h e aulhenllcalron ofresource users vd~l handled (apoltcation-managedor contarnsr-managed). OptionalC, you can define lf Me resource IS sharable and prwlde a descnpZonfor it.

Pro~ramacion de servlets
Avance por el asistente hasta que llegue a la pantalla File references (Referencias de archivo). Aqui configuraremos el archivo techsupp.html que creamos para que fuera la pantalla de bienvenida para esta aplicaci6n Web. Por ello, en lugar de introducir el URL http://localhost:8000/techSupport/techSupp.html, puede Gnicamente introducir http://localhost:800O/techSupport/ en su navegador para cargar este archivo. MBS adelante, en el capitulo 9, discutiremos ampliamente sobre 10s archivoi de bienvenida.

Please pronde a lisl o f t h e w i c w n e files used byyour WAR file Llsl any lag ltbranes referenced by JSPs In Ihrs WAR file, and Indlcale Ihe corfesoondlng lag lrbrarl Also. Ilst am errors or excephons to be trapped and Indicate Ihe tonespondlng resource to be called
Welcorr~e Files

Esto es todo lo que necesitamos para configurar el asistente por lo que puede bien pulsar el b o t h Finish (Finalizar) ahora o bien seguir hasta el final del asistente para ver el descriptor de despliegue. Una vez haya salido del asistente, verj. el componente Web reciCn creado en la ventana principal:

St.wIw hmt \ w y w-~ nr~ pnsnmw

. - .- -. . .. .

Load at anytlme
-

ni=?--

2 - -- .

Capitulo 6
El descriptor de despliegue

Asi es el descriptor de despliegue para esta aplicacion Web:

Configurar la fuente de datos


Antes de que podamos desplegar la aplicaci6n, necesitamos representar la referencia de fuente de datos que realizamos en el asistente a la base de datos que creamos antes. Para ello, abra el cuadro de dialog0 server Configuration (Configuraci6n del servidor) del men6 ~ o o l s (herramientas):

9 O JMS

0%

D Connecbon Factones
Dest~nat~ons

Seleccione el nodo Data sources I Standard, (Origenes de datos I Estlndar) y Cree una nueva fuente de datos llamada jdbc/TechSupport que apunte a la base de datos que creamos:

Programacion de servlets

Desplegar la aplicacion Web


DespuCs de configurar una nueva fuente de datos, necesitarernos reiniciar el servidor J2EE si esti siendo ejecutado para que la fuente de datos sea creada. Si el servidor no ha sido creado, inicie el servidor ejecutando j 2 e e - v e r b o s e desdeeldirectoriot J~EE-HOME% \bin. Conecte ahora la herramienta de despliegue a1 servidor activo, seleccionando ~ d S d e r v e r (Agregar servidor) del menG F i l e (Archivo) y afiadiendo un servidor llamado l o c a l h o s t :

1'

I localhost

Ahora podemos desplegar el componente Web. Seleccione Deploy (Desplegar) del men6 Tools (Herramientas) para iniciar el asistente de despliegue:

Please select the object to be deployed and the s e m r ta which it should be deployed:

p r

Deploy: Techsupport to

Ihe sewer can send back a client JAR file. It contains the extra that client applicationswritten to access this applicationwill need at mntime.

O Return Clienl Jar


:upporfiTechTu~l~nrtl:I~~nt Iar

4 S a w object before deploying


I

Asegh-ese de que estamos desplegando la a p l i c a c i d n ~ e c h s u p p o ry t haga clic en N e x t (Siguiente):

342

Proeramacion de servlets

References
--

Ref Tvpe -Resource

Referenced BY Web ~ p p

I Reference Name

JNDI Name JdbcTT~chSup~or! ~db~flechSu@port

Deberiamos haber configurado el nombre J N D I para la fuente de datos cuando creamos la aplicaci6n pero, si n o lo hizo, puede afiadirlo aqui. Pulse N e x t (Siguiente) para ir a la siguiente p a n d a :

Capitulo 6
C o n f i g u r e c o n t e x t R o o t (Raiz del contesto) de la aplicaci6n para que sea t e c h s u p p o r t . Esto detcrmina el URLpara acceder a la aplicacibn. SeleccioneNext (Siguiente) y despu6s F i n i s h (Finalizar) para iniciar el proceso de despliegue:

~VCIIITI~-:-..

w..

Application Tec hSupport transferred as 0 ejbs, 1web components lo deploy TechSupport h: Deploying Ejbs Processing be:ans ... Making client JI 4Rs ... Making server. JARS ... . . ,. . ..- .. . -. -. .. .. . .;r~nreposaolyrob Contact the wea sewer ana asK r lo run: c:yzsa~eel Veb Components Deployed. Ieployment of TechSupport is complete.
m,,,

Ya estanlos casi preparados para probar nuestra aplicacibn.

Apoyo tecnico en marcha


Hny un paso final que debemos ejccutar antes de que podamos probar esta aplicaci6n. Este paso es iniciar la base de datos Cloudscape. Podemos iniciarla utilizando el archivo c l o u d s c a p e . b a t del directorio " J2EE-HOME4 \binutilizando un c o n m u t a d o r - s t a r t :

Abra un navegador e introduzca el URL http://localhost:800O/techSupport y rellene el forndario:

Programacion de servlets

F i s t Name, l~lexander

Last N m e r ~ a r n s Phone operahng System: windows 2000 Pro

E m d Ixander@sunrydale corn
S o b a r e MicrosohAccess

Problem Descri~tion
Cannor converc database

flied

S~bmd Request

A1 enviar este forniulario, el navegador debe generar la siguiente respuesta:

wctha

Ed~clclm

Yer

Favortor

Herramentar

Ayda

= I

Tech Support: Request Confirmation


Thank you for your request Your request mth the f o l l o ~ e f e r e n c e number has been received
Request Reference 1 references. Please note h s number for fuh~re
n hours Your request wdl be attended to w ~ h 24

Ahstrator Techsupport team

Capitulo 6
Puede utilizar las herramientas facilitadas Dor su vendedor Dara abrir las tablas de la base de datos v saber si 10s datos han sido afiadidos correctamente. En el caso de Cloudscape, puede utilizar la aplicaci6n Cloudview para abrir la base de datos:

Asegrirese de qrre cierra la base de datos Clorrdscape antes de arrancar C1oudVie-w. Esto es asiporque, en la configuraci6n por defecto, Cloudscape permite el acceso a los archiwos de la h s e de datos desde urza s o h aplicrrci6n a la uez.

Resumen
El API Java Servlet es sencillo y muy capaz. Nos permite ampliar la funcionalidad de cualquier servidor Web, con la ayuda de un simple modelo de programaci6n. El objetivo de este capitulo ha sido presentar el API Servlet y el ciclo de vida de 10s servlets, y demostrar c6mo escribir aplicaciones basadas en servlets. En este proceso, hemos abarcado 10s siguientes puntos:
3 Al construir un servlet, necesita implementar la interfar s e r v l e t . Puede implementarla

a m p l i a n d o l a c l a s e ~ e n e r i c ~ e r v lo eH t ttpServlet.
O

La c l a s e ~ t t p ~ e r vaem t p l i a ~ e n e r i c s e r v l ey t proporciona funcionalidad especifica HTTP adicional. Los servlets pueden implementar la interfaz S i n g l e T h r e a d M o d e l para imponer acceso sincronizado a 10s mitodos de servicio. Sin embargo, 10s servlets que no implementan esta interfaz deben certificar que se accede a cualquier variable de instancia de servlet de un mod0 a salvo de amenazas. Hemos analizado las implicaciones de 10s servlets F r e a k s e r v l e t y TechSupportServlet.

Pro~ramacion de servlets
0 0 0

El ciclo de vida de 10s servlets implica 10s rnitodos i n i t ( ) , s e r v i c e ( ) y d e s t r o y ( ) . El FreakServlet demuestra 10s estados asociados a1 ciclo de vida de una instancia de servlet. Utilizamos descriptores de despliegue para especificar 10s parimetros de inicializaci6n. Esto nos ayuda a evitar la codificaci6n de tales parimetros dentro de 10s servlets. Puede utilizar piginas de error para enviar,autorniticamente piginas HTML predisefiadas en respuesta a errores H T T P y excepciones. Este es un enfoque muy flexible y e s una buena prictica para el manejo adecuado de errores y evitar que mensajes desagradables generados por el contenedor sean enviados a 10s clientes.

En el siguiente capitulo, examinarernos otra parte del API Servlet, que se centra en sesiones, contextos y colaboraciones de servlet.

Sesiones de servlets, context0 y colaboracion


En 10s dos capitulos anteriores, hemos cubierto 10s aspectos bisicos del API Servlet. En particular, hemos analizado el ciclo de vida de 10s servlets y 10s API para leer solicitudes y escribir respuestas de vuelta a 10s clientes. Estos aspectos del API Servlet le equipan para construir servlets que generen piginas Web dinimicas. U n servlet recibe un objeto solicitud, extrae parimetros (si hay alguno) del objeto, procesa cualquier 16gica de aplicaci6n (que puede depender de 10s parimetros de solicitud) y, finalmente, genera la respuesti. Ampliando este modelo, puede construir mayores aplicaciones Web contando con varios servlets, con cada servlet realizando una tarea independiente perfectamente defini+. Este modelo es adecuado siempre que la 16gica de aplicaci6n en cada uno de estos servlets sea atbmica, es decir, siempre que la 16gica de aplicaci6n dependa s61o de 10s parimetros de la solicitud (y, si es aplicable, cualquier dato persistente como 10s datos almacenados en la base de datos relational). Por ejemplo, en la aplicaci6n de Apoyo Tkcnico el servlet consigue todos 10s datos de la solicitud de apoyo de la solicitud y, como parte de la bgica de aplicaci6r1, escribe 10s datos de la solicitud a una base de datos y envia de vuelta una confirmaci6n. Considere ahora una aplicaci6n Web familiar: una tienda online. En una tipica tienda online, la aplicaci6n principal que controla la tienda es un carro de la compra. Una tienda online le proporciona una interfaz navegable para un catilogo. Puede seleccionar articulos en el catilogo y afiadirlos a1 carro de la compra. Una vez que ha afiadido todos 10s articulos requeridos a1 carro, se dirige a la caja y presenta un pedido de 10s articulos en el carro. Sin embargo, una aplicaci6n de este tip0 no es tan sencilla como parece. iD6nde se mantiene el carro de la compra? Puesto que el cliente es "infradotado", es responsabilidad del servidor mantener el carro no s61o para nosotros sino para el resto de usuarios que pueden estar navegando el catilogo simultineamente y afiadiendo articulos a sus respectivos carros de la compra. Para que este mecanismo funcione, el servidor deberia poder distinguir individualmente a cada usuario y, de acuerdo con ello, mantener cada carro de la compra. i C 6 m o construimos esta funci6n en una aplicaci6n Web?

Capitulo 7
~ s t es e un requisito tipico para aplicaciones Web, en las que la "actividad de usuario" tiene lugar en multiples solicitudes y respuest*, y es necesario que el servidor asocie algun tip0 de exclusividad a cada usuario. En la primera parte de este capitulo, analizaremos lo que se conoce como registro de sesi6n para enfrentarnos a este requisito. Examinaremos algunos enfoques de registro de sesi6n, en particular 10s utilizados por el API Servlet Java. Ademds del registro de sesi6n, consideraremos otra instalacidn util que proporciona el API Servlet. Como hemos visto en el capitulo 6,los servlets son parte de las aplicaciones Web y la noci6n de una aplicaci6n Web se construye en lo que se denomina contexto de servlet. En tkrminos sencillos, un contexto es una visi6n de la aplicacidn Web y el contenedor Web. Los servlets de una aplicacidn pueden utilizar este contexto para intercambiar informaci6n, o colaborar con otros servlets, acceder a recursos, registrar eventos, etc. En la segunda parte de este capitulo, analizaremos 10s API Servlet relacionados con el contexto de servlet. Para demostrar c6mo el registro de sesi6n y el contexto de servlet le permiten construir complejas aplicaciones Web, tambikn estudiaremos una aplicaci6n chat online, donde multiples usuarios pueden visitar la pdgina, crear una sala de chat, unirse a una sala de chat, e intercambiar mensajes con otros miembros de una sala de chat. Finalmente, el ejemplo de Apoyo Tkcnico del hltimo capitulo serd revisado para demostrar una instalaci6n de servlet mis Gtil: colaboraci6n de servlet, que puede utilizarse para conseguir que una serie de servlets funcione a la vez para generar la respuesta a una solicitud. Aunque el ana'lisis de este capitulo se centra en 10s servlets, las ideas generales tambie'n son aplicables a aplicaciones Web de base JSP.

Protocolo sin estado y sesiones


H'ITP es un protocolo sin estado. Un cliente abre una conexi6n y solicita algGn recurso o inforrnaci6n. El servidor responde con el recurso solicitado (si estd disponible), o envia un estado de error H'ITP. DespuCs de cerrar la conexi6n, el servidor no recuerda ninguna informaci6n sobre el cliente. Por lo tanto, el servidor considera la siguiente soli~itud procedente del mismo cliente como una solicitud nueva, sin relaci6n alguna con la solicitud anterior. Esta es la funci6n de un protocolo H'ITP sin estado. U n protocolo con estado es aquel en el que la respuesta a una solicitud dada puede depender no s610 de la solicitud actual sino tambikn del resultado de solicitudesanteriores. Normalmente, en un protocolo con estado, mkltiples solicitudes y respuestas de cliente son enviadas a travks de una Gnica conexi6n de red entre el cliente y el servidor. Basindose en esta conexi61-1,el servidor puede identificar tales solicitudes como parte integrante de una Gnica sesi6n. Por ejemplo, considere el protocolo de transferencia de archivos (FTP). FTP es un protocolo con estado, con mGltiples solicitudes y respuestas de cliente en una Gnica conexi6n en una sesi6n determinada. En este caso, la conexi6n se establece con el primer comando OPEN y se cierra despuks del comando E X I T (a no ser, por supuesto, que un fallo de la red termine la conexi6n). Consecuentemente, el servidor FTP puede asociar todas las solicitudes de cliente a una Gnica sesi6n con el cliente. El servidor tambikn puede tomar decisiones basadas en el estado de la sesi6n. Por ejemplo, un servidor FTP puede limitar el n6mero de solicitudes GET (para la descarga de archivos) dentro de una sesi6n. Pero, {par quk es importante tener estado? U n protocolo con estado le ayuda a desarrollar una 16gica compleja de aplicaci6n en mdltiples solicitudes y respuestas. Consideremos un banco online. Cuando solicita una pigina que contiene 10s balances de todas sus cuentas, el servidor debe poder verificar que es el verdadero titular de la cuenta y que ha demostrado sus credenciales a1 banco online. Sin embargo, cuando

Sesiones de servlets. context0 v colaboracion


el protocolo no tiene estado, seri necesario que envie sus credenciales con cada solicitud; de hecho, cada transacci6n cornercial deberi tener lugar en una unica solicitud. Este metodo no es recornendable para largas transacciones cornerciales que deben desarrollarse en multiples solicitudes, corno en el banco online, o en el carro de la cornpra que hernos visto hace un rnornento. Para irnplernentar transacciones cornerciales flexibles en multiples solicitudes y respuestas, necesitarnos dos instalaciones:
0

Sesi6n El servidor debe ser capaz de identificar que una serie de solicitudes de un unico cliente forrnan una unica "sesi6n" de trabajo. Asociando una solicitud especifica para que pertenezca a una sesi6n especifica de trabajo, la aplicaci6n del carro de la cornpra o el banco online pueden distinguir un usuario de otro. Estado El servidor debe ser capaz de recordar inforrnaci6n relacionada con solicitudes anteriores y otras decisiones comerciales que son realizadas para las solicitudes. Es decir, la aplicaci6n deberia ser capaz de asociar estado con cada sesi6n. En el caso de la aplicacion del carro de la cornpra, el posible estado podria incluir las categorias de articulos favoritos del usuario, perfil del usuario, o incluso el rnisrno carro de la cornpra.

Sin embargo, en el caso de HTTP, las conexiones son cerradas a1 final de cada solicitud y por ello 10s servidores HTTP no pueden utilizar la noci6n de conexiones para establecer una sesi6n. HTTP es un protocolo sin estado, que se ocupa de solicitudes y respuestas, que son transacciones sencillas y aisladas. Es perfecto para navegar webs sencillas, donde cada solicitud produce norrnalrnente descargas de contenido estitico. El servidor no necesita saber si una serie de solicitudes procede del rnisrno o de diferentes clientes, o si esas solicitudes estin relacionadas o son independientes. Pero kste no es el caso de las aplicaciones Web, donde necesitarnos la capacidad para realizar transacciones comerciales en multiples solicitudes y respuestas. C o n HTTP, en una transacci6n que produce multiples solicitudes y respuestas, el servidor Web no puede deterrninar si todas las solicitudes proceden del rnisrno cliente. U n cliente, por lo tanto, no puede establecer un diilogo con el servidor Web para realizar una transaction econ6rnica. Sin embargo, el objetivo de HTTP ha sido proporcionar una recuperaci6n de inforrnaci6n rapida y ligera en Internet y un protocolo sin estado es lo rnis adecuado para estos requisitos. Aparte de poder registra usuarios basandose en la noci6n de sesiones, el servidor tarnbih deberia ser capaz de recordar cualquier inforrnaci6n necesaria dentro de una sesi6n. Es decir, el programador de la aplicaci6n debe ser capaz de especificar quC datos deben ser recordados en una sesibn, de rnodo que la aplicaci6n pueda utilizar esa inforrnaci6n para tornar decisiones rnis inforrnadas. Esto resulta rnuy util para transacciones o procesos que producen multiples solicitudes y respuestas. C o n protocolos con estado, el servidor asocia un estado a la conexibn: recuerda q u i h es el usuario y quC esti haciendo, con la ayuda de la conexion. Sin embargo, esto no se puede conseguir con HTTP, puesto que la vida de una conexidn se lirnita a una h i c a solicitud. C o n el tiernpo, diversas estrategias han evolucionado para tratar el registro de sesi6n y para gestionar el estado en una sesi6n. El API Java Servlet proporciona funciones para registrar sesiones y rnantener el estado en una sesi6n deterrninada. Con la ayuda de estas funciones, el servidor puede asociar todas las solicitudes juntas y saber que todas proceden del rnisrno usuario. TarnbiCn puede asociar un estado con la conexi6n: recuerda quiCn es el usuario y quC esti haciendo.

Observe que H T T P 1.1 (http:llwww.w3.orglProtoco/slrfc2068lrfc2068)proporciona "conexiones persistentes", en cuyo caso clientes y servidores pueden utilizar el mismo objeto de conexion para multiples solicitudeslrespuesta. Cuando son apoyadas por clientes y servidores, las conexiones persistentes reducen la demora asociada a la creaci6n de conexiones TCPIIP. Las conexiones

Capitulo 7
persistentes son utiles en casos en 10s que solicitudes y respuestas que se suceden rapidamente pueden ser optimizadas utilizando una unica conexidn en lugar de una conexidn por cada solicitud. Sin embargo, las conexiones persistentes no llevan estado. El ana'lisis de este capitulo se mantiene igual con las conexiones persistentes.

Enfoques del registro de sesion


Existen fundarnentalrnente cuatro rnodos de enfocar el registro de sesi6n:
O

ReescrituraURL

o Carnpos de forrnulario ocultos

o Cookies o Sesiones que utilizan la capa Secure Sockets Layer (SSL)


Observe que algunos libros sugieren la autentificacidn de usuario corno un medio de registro de sesidn. Pero la autentificacidn de usuario es una decisidn de nivel de aplicacidn y no todas las aplicaciones requieren autentificacidn de usuario para todos 10s recursos de una aplicacidn Web.
Aunque 10s cuatro enfoques anteriores difieren en detalles de irnplernentaci6n, todos ellos estin basados en un sencillo truco: intercarnbiar algGn tip0 de testigo entre el cliente y el servidor. Considere un cliente C y un servidor S. Cuando C envia una solicitud a S por prirnera vez, S da a C un testigo Gnico. Este testigo puede ser tan sencillo o tan cornplejo corno querarnos que sea: un nGrnero, un nornbre d e usuario, o una cadena ID de sesi6n. Siernpre que C visita S de nuevo, tarnbien envia el testigo junto con la solicitud. S puede ahora reconocer a C por su testigo. Esto es lo esencial de un registro de sesi6n:

Esta sencilla tecnica para el registro de sesi6n puede ser adaptada de diferentes forrnas, basindose en c6rno el testigo puede ser representado e intercambiado. Considerernos ahora 10s cuatro enfoques anteriores y c6rno estos enfoques representan 10s testigos y c6rno estos testigos son intercarnbiados en estos enfoques:
O

Reescritura de U R L En este enfoque, el testigo es integrado en cada URL. En cada pigina generada dinirnicarnente, el servidor integra un parirnetro extra de consults, o inforrnaci6n de ruta extra, en cada URL de la pigina. Cuando el cliente envia las solicitudes utilizando estos URL, el testigo es transrnitido de nuevo a1 servidor. Este enfoque se denornina reescritura de URL, ya que conlleva rescribir URL en el contenido de la respuesta para integrar en testigo extra. Este enfoque es similar a la reescritura de URL. En lugar de rescribir cada URL, el sewidor integra carnpos ocultos en cada forrnulario. Cuando el cliente envia un forrnulario, 10s carnpos adicionales

o Campos de formulario ocultos

Sesiones de servlets, context0 y colaboracion


tambikn serin enviados en la solicitud. El servidor puede utilizar estos parimetros para establecer y rnantener una sesidn.
0

Cookies Los cookies fueron inventados por Netscape y son una de las formas mis refinadas de testigo que clientes y servidores pueden intercambiar. A diferencia de rescribir URL o de utilizar campos de forrnulario ocultos, 10s cookies pueden ser intercarnbiados en cabeceras de solicitudes y respuestas, y por lo tanto no suponen manipular la respuesta generada para que contenga un testigo.
Sesiones de Secure Socket Layer (SSL) SSL es una tecnologia de cifrado que se ejecuta sobre TCP/IP y bajo protocolos de nivel de aplicacidn como HTTP. SSL es la tecnologia utilizada en el protocolo H'ITPS. Los servidores con SSL pueden autentificar a clientes habilitados con SSL y utilizar una conexi611 cifrada entre cliente y servidor. En el proceso de establecer una conexidn cifrada, tanto el cliente como el servidor generan lo que se denomina "claves de sesi6nU, que son claves simktricas utilizadas para cifrar y descifrar mensajes. Los servidores basados en el protocolo HTTPS pueden utilizar la clave simktrica del cliente para establecer una sesi6n.

Pero, c'corno podemos elegir entre estos enfoques y establecer y mantener sesiones en nuestras aplicaciones Web? La respuesta es que, con servlets, es responsabilidad del contenedor W e b proporcionar las instalaciones bisicas para crear y mantener sesiones. La especificacidn del servlet permite a 10s contenedores Web utilizar la reescritura de URL, cookies, o sesiones SSL para el registro de sesion. La verdadera ticnica utilizada para establecer y registrar una determinada sesidn depende de la capacidad del servidor y de la del cliente para participar en sesiones. El API Servlet tambiin le ofrece una interfaz, cuyos objetos le permiten manipular el ciclo de vida de la sesidn y asociar estado con sesiones. Existen ciertas directrices que certifican que el registro de sesidn con independencia de la tkcnica utilizada. Antes de examinar 10s componentes del API Servlet para registro de sesi6n, analicemos 10s tres primeros enfoques con mis detalle.

Reescritura de URL
Corno hemos visto en 10s capitulos anteriores, una solicitud H T T P consiste en la ubicaci6n del recurso del servidor (URL), seguida opcionalmente por una cadena de consulta que contiene pares de parimetros y valores. U n ejemplo de un URL es:

En este ejernplo, el servidor es www .my s e r v e r . corn, la ruta de recurso es / s e r v l e t / g e t ~ c h e d u l e ; u i d = j o ylacadenade~onsultaesbe~~eriod=3&end-~eriod=6. e Normalrnente, 10s navegadores generan tales solicitudes al enviar formularios con A C T I N O tip0 GET. Si utiliza solicitudes POST en sus forrnularios, 10s dos parimetros de consulta formaran parte del cuerpo. Cada informacion extra de ruta del URL asi como 10s parimetros de consulta pueden ser extraidos del o b j e t o ~ t t p ~ e r v l e t ~ e q udesde e s t dentro de su servlet. La reescritura de URL utiliza la misrna tkcnica para integrar testigos unicos especificos del cliente en cada URL. Por ejemplo, a continuaci6n, cada ruta de URL tiene una cadenauid= j o e adjunta, donde u i d es un parimetro exclusive para cada usuario, con valor j oe:
<ul> <li><a href="http://www.myserver.com/servlet/~~rmenu;uid=joe"> User Prefs</a> </li>

Capitulo 7
< l i > < a href="http://www.myserver.com/servlet/tsEntry;uid=joe"> Time Sheets</a> </li> < l i > < A HREF="http://www.myserver . c o m / s e r v l e t / e x E r ~ t r y ; u i d = ] o e " > Exp Form</a> </li> . </ul>

Por el mornento, asumamos que el servlet ha generado este contenido dinimico, posponiendo la cuestidn de como puede realizarse esto con el API Servlet. Cuando el servlet genera el fragmento de cbdigo anterior, integra en u i d dentro de cada URL. Cuando el usuario hace clic en cualquiera de estos hipervinculos, el u i d es pasado junto con la solicitud a1 contenedor Web. El contenedor Web puede entonces obtener el valor del u i d desde la solicitud. Como hemos analizado en la seccibn anterior, el servidor envia el testigo como parte del URL y el cliente lo envia de vuelta junto con la solicitud, otorgando asi a1 contenedor la capacidad de registrar la sesion de j o e . Este enfoque se denomina reescritura de URL ya que conlleva rescribir todos 10s URL para incluir un testigo exclusivo en la ruta de URL. Aunque hemos utilizado un parimetro uid en el ejemplo anterior, el nornbre del parimetro especificado en la especificacidn del servlet es jsessionid. El verdadero URL generado es similar a1 siguiente:

La reescritura de URL requiere que todas las piginas de la aplicacidn Sean generadas dinimicamente. La reescritura de URL no puede ser aplicada en piginas HTML porque el exclusivo parimetro de ruta URL (el j s e s s i o n i d ) es dinimico y difiere entre usuarios. Observe tambikn que el j s e s s i o n i d (o el u i d del ejemplo anterior) es un parirnetro de ruta y no un parimetro de consulta (corno las solicitudes GET). de consulta son pares valor-nornbre separados por "&", mientras que el parimetro de ruta Los parimet~os j s e s s i o n i d = < ...> es una ruta de recurso codificada.

Campos de formulario ocultos


En este enfoque, el testigo exclusivo esti integrado en cada formulario HTML. Por e j e m ~ l oel , siguiente HTML especifica un control de entrada de tipo H i d d e n :
<input t y p e = " H i d d e n W name-"uid" value=="joen>

Cuando la solicitud es enviada, el servidor recibe el testigo como parte de la solicitud. Observe que, similar a la reescritura de URL, el contenido anterior debe ser generado dinimicamente integando el parimetro. oculto. Ademis, cada solicitud debe incluir una presentacidn de formulario y por ello puede no ser aplicable a todos 10s tipos de piginas. La especificacidn de servlet no utiliza este enfoque.

Los cookies son 10s medios de registro de sesi6n de cliente mis comlinmente utilizados. Los cookies fueron introducidos inicialmente por Netscape y esta tecnologia fue rnis tarde normalizada en RFC 2109 (http://www.faqs.org/rfcs/rfc2109.html). Tarnbikn puede leer la especificaci6n preliminar de Netscape en http://www.netscape .com/newsref/std/cookie~spec. html.

U n cookie es un pequefio fragmento de informaci6n textual enviado por el servidor a1 cliente, almacenado en el cliente y devuelto por el cliente para todas las solicitudes del sewidor.

Sesiones de servlets, context0 y colaboracion


Un cookie contiene uno o mis pares valor-nornbre con ciertos atributos adicionales, que son intercambiados en las cabeceras de respuesta y solicitud. Los senidores Web envian un cookie enviando una cabecera de respuesta S e t - C o o k i e en el siguiente formato: S e t - C o o k i e : Name=VALUE; Comment=COMMENT; Domain=DOMAINNAME; Maxage=SECONDS; Path=PATH; s e c u r e ; Version=l*DIGIT Aqui Name es el nombre del cookie y VALUE es el valor de Name, Max- a g e (opcional) especifica la vida mixima del cookie en segundos, Domain (opcional) y P a t h (opcional) especifican la ruta URL para la que es vilida el cookie y s e c u r e (opcional) especifica si el cookie puede ser intercambiado sobre HTTP. Para 10s cookies implementados como por RFC 2 109, la V e r s i o n debe ser configurada en 1. La V e r s i o n debe ser configurada en 0para 10s cookies implementados como por la especificacidn de Netscape. comment es un pardmetro opcional que puede utilizarse para documentar el objetivo del cookie. ~ s t es e un ejemplo de un cookie:

La cabecera de respuesta anterior envia un cookie con nombre u i d y valor j o e . La vida de este cookie es de 3600 segundos y es vdlido para el dominio m y s e r v e r . com (incluidos todos 10s subdominios) para la ruta URL /. El navegador debe descartar este cookie despuks de 3600 segundos. Si falta el atributoMaxa g e , el navegador descarta el cookie a1 salir del navegador. En lugar de especificarmyse r v e r . comcomo dominio, tambiCn puede especificar subdominios como www.myserver. c o m o some . m y s e r v e r . cometc., en cuyo caso el navegador sdlo devuelve elcookie a 10s subdominios especificados. Por ejemplo, 10s portales de informacidn como Yahoo especifican en todo momento el dominio completo . y a h o o . coma1 configurar cookies, de modo que Yahoo pueda .. identificar/registrarle si esti visitando http://my.yahoo.com, o comprando en http://shop.yahoo.com, o comprobando su correo en http://mail.yahoo.com. Cuando un cliente navegador recibe la cabecera de respuesta anterior, puede rechazarla o aceptarla. Por ejemplo, puede configurar su navegador para aceptar o rechazar cookies. Consideremos que el navegador acepta este cookie. Cuando el navegador envia una solicitud a1 dominio http://www.myserver.com en la pr6xima hora, tambikn envia una cabecera de solicitud:
Cookie: uid=joe

El senidor puede leer este cookie desde la solicitud, e identificar que la solicitud corresponde a un cliente identificado por u i d = j oe. Esto completa el intercambio de testigos necesario para registrar sesiones. U n cookie es especifico de un dominio o un subdominio y puede ser establecido por el atributo de dominio en el cookie. Los navegadores utilizan 10s atributos de dominio y ruta para determinar si un cookie debe ser enviado en la cabecera de la solicitud y con quk atributos de valor nombre. Una vez aceptado por un navegador, el navegador almacena el cookie junto a1 dominio y la ruta URL. Si el cliente escoge rechazar un cookie, el cliente no envia el cookie de vuelta a1 senidor en la cabecera de solicitud y, por lo tanto, el senidor no consigue registrar la sesidn de usuario. Observe que la principal ventaja de este enfoque es que 10s cookies no se mezclan con el contenido HTML y 10s cuerpos de la solicitud y la respuesta HTTP. El contenedor puede configurar cookies transparentemente en las cabeceras de la respuesta y extraer cookies de las cabeceras de la solicitud. La especificaci6n del API Senlet requiere que 10s contenedores Web implementen el registro de sesi6n utilizando el mecanismo de cookie. En este enfoque, el contenedor Web configura automiticamente un cookie de registro de sesidn con nombre j s e s s i o n i d . Cuando el contenedor recibe las solicitudes del cliente, comprueba la existencia de este cookie y registra las sesiones consecuentemente.

Capitulo 7
Sin embargo, puesto que 10s servidores pueden configurar cookies transparentemente, que son almacenados en el ordenador del usuario y enviados de vuelta al servidor, 10s cookies provocan preocupaciones de seguridad para muchos usuarios. Remitase a http://www.w3.orglSecurity/Faql wwwsf7.html y http://www.~ia~.org.cia~/b~lIetin/i-034sht para un anilisis de problemas de seguridad con cookies. Para resolver tales inquietudes, 10s navegadores le permiten inhabilitar cookies. Cuando 10s cookies son inhabilitados, 10s contenedores de servlet utilizan la reescritura de URL para registra sesiones. Aunque diversos sitios requieren cookies y proporcionan funcionalidad limitada o nula cuando 10s cookies son inhabilitados, es una buena pra'ctica diseiiar aplicaciones Web que se ajusten a la reescritura de URL. Aparte de 10s cookies de registro de sesibn, sus aplicaciones Web pueden configurar cookies explicitamente en la respuesta. Utilizwdo el API Servlet, puede aiiadir varios cookies en la respuesta y extraer cookies de la solicitud. El API Servlet proporciona una clase llamada j a v a x . s e r v l e t .h t t p .C o o k i e que represents uncookie desde la perspectiva del servlet. El servlet puede crear un nuevo cookie, configurar su nombre y valor, configurar edad mixima, etc. y despues aiiadir el cookie a1 objeto H t t p S e r v l e t R e s p o n s e para enviarlo de vuelta a1 navegador. Los cookies tambien pueden ser recuperados desde el objeto H t t p S e r v l e t R e q u e s t y sus valores pueden ser leidos. Para el prop6sito de nuestro anilisis actual, puede configurar el cookie anterior utilizando el siguiente c6digo en su servlet:
//
C r e a r un s o o k i e Nuevo c o n a r g u r n e n t o s d e nornbre C o o k i e c = new C o o k i e ( " u i d W , " j o e " ) ;
y valor

//

Confiqurar l a v i d a d e l cookie c . setMaxAge (60*60) ; / / E x p i r a e n una c . s e t D o r n a i n [ " . m y s e r v e r . corn"); c.setPath("/");

hora

/ / E r ~ v i a r e l cookie a 1 navegador p a r a cliente r e s p o n s e . a d d c o o k i e ( c );

que

sea

alrnacenado

en

la

rndquina

De un modo similar, puede recuperarcookies de solicitudes utilizando el metodo g e t c o o k i e s ( ) en la interfaz~ttp~ervler~esponse. Posibles aplicaciones para configurar cookies explicitos incluyen marketing dirigido, personalizaci6n de sitios, registro de uso, etc.

Registro de sesion con el API Java Servlet


En el API Java Servlet, lainterfaz j a v a x . s e r v l e t .h t t p . H t t p S e s s i o n encapsula la noci6n de sesi6n. Los contenedores Web proporcionan una implementaci6n de esta interfaz. Puesto que la noci6n de sesion esti asociada a solicitudes de cliente, la interfaz H t t p s e r v l e t R e q u e s t proporciona el metodo g e t s e s s i o n ( ) ,que puede utilizar para acceder al o b j e t o ~ t t pe s s s i o n asociado con el cliente que realiza la solicitud. Si se remite a1 diagrama de clase para el paquete javax.servlet.http, obsrrvari que hay una flecha entre las interfaces ~ t t p s e r v l e t ~ e q u eys~t t t p s e s s i o n Esto . significa s t , obtener e l o b j e t o ~ t t p ~ e s s i o n . que, dadoun o b j e t o ~ t t p ~ e r v l e t R e q u e puede Para asociar estados a sesiones, la interfaz ~ t t p s e s s i o n proporciona mktodos con 10s que podemos configurar y obtener atributos de 10s objetos ~ t t p ~ e s s i o n . Como hemos mencionado, 10s contenedores Web utilizan cookies o reescritura de URL para establecer sesiones. Mientras que la mayoria de contenedores Web confian s61o en cookies para establecer sesiones,

Sesiones de servlets, context0 v colaboracion


algunos utilizan cookies por defect0 y utilizan la reescritura de U R L cuando 10s clientes rechazan 10s cookies. La verdadera creacidn de sesiones es transparente para el programador de aplicaciones. Es decir, no necesita explicitamente crear, configurar, u obtener cookies, o rescribir URL para el registro de sesiones. C o m o veri m i s adelante, el h i c o requisito es que debe codificar todos 10s U R L de la respuesta. El API Servlet para el registro de sesi6n consiste en lo siguiente: Mktodos de lainterfaz j a v a x . s e r v l e t .h t t p . H t t p S e r v l e t R e q u e s t paracrearyaccedera objetos~tt~~ession. Una interfaz j a v a x . s e r v l e t .h t t p .H t t p S e s s i o n para representar sesiones. Esta interfaz incluye mktodos para asociar estado a sesiones y para configurar e invalidar sesiones.

Mktodosdelainterfazjavax. s e r v l e t .h t t p . H t t p ~ e r v l e t R e s p o n s e p a r a c o d i f i c a r U R L d e mod0 que el contenedor Web pueda utilizar la reescritura de URL cuando 10s cookies son rechazados por navegadores de cliente.
Lainterfazj a v a x .s e r v l e t .h t t p .~ t t p ~ e s s i o n ~ i n d i n g ~ i s t e n e r y l a c l a s e j a v a x .s e r v l e t . h t t p H t t p S e s s ionBindingEvent,pararepresentareventos asociados asesiones.

Analizaremos cada uno de estos elementos en las siguientes secciones.

Creacion y registro de sesiones


Los mktodos de la interfaz H t t p S e r v l e t R e q u e s t para crear y registrar objetos H t t p s e s s i o n son 10s siguientes:
public HttpSession getSession(boo1ean create) ; public HttpSession getsession();

Cada uno de estos mktodos devuelve el objeto H t t p s e s s i o n asociado a la solicitud actual. Si no hay ninguna sesi6n asociada a la solicitud actual, el segundo mktodo crea uno. Esto puede suceder cuando el cliente rechaza unirse a una sesibn, por ejemplo cuando el usuario inhabilita cookies en su navegador. El primer toma un argumento adicional Booleano, para indicar si el contenedor debe intentar crear una nueva sesi6n si no hay sesi6n asociada a la solicitud actual. Si este argumento es f a l s e y si no hay sesion asociada a la solicitud, este metodo devuelvenull. Desde la perspectiva del servlet, la creaci6n/registro de sesidn conlleva invocar uno de estos dos mktodos para obtener un objeto H t t p S e s s i o n . Sin embargo, desde la perspectiva del contenedor Web hay mis. C o m o hemos visto en la secci6n anterior, la creacion de sesidn implica establecer un testigo (basado en un cookie, o el parimetro de ruta URL, o una clave de sesion SSL) que puede ser intercambiado entre el cliente y el servidor y asociar un testigo de este tipo a un objeto H t t p S e s s i o n . El contenedor Web recibe el testigo como parte de la solicitud. Cuando el mCtodo g e t s e s s i o n ( ) es invocado, el contenedor recupera el objeto ~ t t p ~ ei o s ns, basado en este testigo. En otras palabras, la creaci6n/registro de sesi6n significa que el contenedor Web es capaz de asociar una solicitud a un cliente y el objeto H t t p s e s s i o n representa esta asociaci6n. El contenedor Web mantiene este objeto durante la sesi6n de cliente, o un period0 de tiempo limite configurable. Puesto que puede haber varios clientes enviando solicitudes a1 contenedor, el contenedor mantiene objetos H t t p S e s s i o n separados para cada cliente. Consecuentemente, puede asociar estado a c a d a ~ t t p ~ e s s i o como n , veri en breve.

La interfaz HttpSession
public interface HttpSession

Capitulo 7
Esta interfaz del paquete j a v a x s e r v l e t .h t t p encapsula la nocibn de una sesibn. U n objeto de este . tip0 puede obtenerseutilizando el m k t o d o g e t s e s s i o n ( ) del o b j e t o H t t p S e r v l e t ~ e q u e s tObserve que, como con la mayoria de las otras interfaces API Servlet que hemos examinado hasta ahora, 10s contenedores Web proporcionan internamente una implementaci6n adecuada y lo que ve es una instancia ( ) del o b j e t o ~ t t p S e r v l e t ~ e q u e s t . obtenidaa travks del m C t o d o g e t ~ e s s i o n La interfaz H t t p S e s s i o n tiene 10s siguientes mktodos:
public public public public public public pub1 ic public public public public Object getAttribute (String name) Enumeration getAttributeNames0 long getCreationTime0 String getId() long getLastAccessedTime0 int getMaxInactiveInterval0 void invalidate ( ) boolean isNew 0 void removeAttribute(8tring name) void setAttribute (String name, Object attribute) void setMaxInactiveInterval (int interval)

Estos metodos pueden ser divididos en dos categorias:


0

Mitodos para vida d e sesion: getCreationTime ( ) getId 0 getLastAccessTime ( ) getMaxInactiveInterval() invalidate () isNew ( ) set~ax~nactive~nterval()

0 Mitodos para asociar atributos (estado) a sesiones: getAttribute () getAttributeNames () removeAttribute () set~ttributeo

Metodos para vida de sesion


Puesto que las sesiones son mantenidas en el lado servidor y puesto que H T T P es un protocolo sin estado, el contenedor Web n o puede determinar si el cliente pretende continuar utilizando la aplicaci6n Web. Por ejemplo, considere una aplicaci6n de correo de base Web, como Microsoft Hotmail. DespuCs de leer 10s mensajes durante un rato, puede cerrar el navegador sin abandonar realmente la cuenta de correo. Observe que el servidor n o puede detectar esto. A medida que aumenta el numero de usuarios para una aplicaci6n Web, el numero de sesiones tambikn aumenta. Cada sesi6n consume memoria en el lado servidor, por lo que n o es muy conveniente mantener mucho tiempo vivas las sesiones. C o m o veremos mis adelante, debe utilizar el elemento < s e s s i o n - c o n f i g > de descriptor de despliegue para especificar un intervalo razonable basado en la sensibilidad de 10s datos compartidos en una sesi6n. Por ejemplo, la mayoria de sitios de e-comercio limitan este intervalo a menos de 30 minutos, mientras que portales como Yahoo utilizan intervalos mls largos. Para gestionar de un mod0 efectivo la vida de la sesibn, el API Servlet proporciona varios metodos.

Sesiones de servlets, context0 y colaboracion


El d t o d o getcreationTim0
public long getCreationTime
()

Este metodo devuelve la fecha en que la sesi6n ha sido creada, en milisegundos desde el 1 de Enero de 1970 00:00:00 GMT.

El d t o d o getldo
public String getId()

Este mitodo devuelve un s t r i n g que contiene un identificador exclusive asignado a esta sesi6n. Este S t r i n g depende de la implementaci6n.

El d t o d o getLastAccessedTim0
public long getLastAccessedTime()

Este metodo devuelve la fecha y el momento en el que el cliente accedi6 a la sesi6n por ultima vez, en milisegundos desde el 1 de Enero de 1970 00:00:00 GMT. Este mitodo puede ser utilizado para determinar el periodo de inactividad entre dos solicitudes consecutivas de un cliente.

El d t o d o getMaxlnactivelntewaIO
public int getMaxInactiveInterval()

Este devuelve el tiempo en segundos que la sesi6n permaneceri activa entre solicitudes antes de expirar.

El d t o d o setMaxlnactivelntewaI0
public void setMaxInactiveInterval(int interval)

Este mttodo establece el tiempo en segundos que la sesi6n se mantendri activa entre solicitudes entes de expirar. Puede utilizar este metodo para configurar programiticamente el intervalo de inactividad de la sesi6n. El contenedor Web certifica que la sesi6n queda automiticamente invalidad despuis de la expiraci6n de este intervalo. Alternativamente, puede utilizar la e t i q u e t a < s e s s i o n - t i m e o u t > en el descriptor de despliegue para especificar el periodo miximo de inactividad:

Aunque el segundo enfoque le permite especificar el intervalo de inactividad para la aplicaci6r1, el primer enfoque le permite cambiarlo programiticamente. A1 transcurrir este intervalo, el contenedor Web invalida automiticamente la sesi6n.

public boolean isNew ( )

Este mitodo devuelve t r u e si la sesi6n ha sido creada en el servidor per0 el cliente todavia no tiene conocimiento sobre ello. U n cliente es considerado como candidato a unirse a una sesi6n cuando el cliente devuelve informaci6n de registro de sesi6n previamente enviada por el servidor. Cuando el cliente rechaza unirse a la sesi611, este metodo devuelve t r u e , indicando que es una sesi6n nueva. Esto puede

Capitulo 7
ocurrir, por ejemplo, cuando el contenedor Web utiliza s61o cookies para el registro de sesibn y el cliente se niega a aceptar cookies.

public void

invalidate0

Puede utilizar este metodo para finalizar sesiones. Por ejemplo, puede utilizar invalidaci6n explicita de la sesi6n para implementar una funcibn de salida en su aplicacibn. Cuando el usuario elige salir, su servidor puede invalidar la sesibn, de mod0 que el usuario ya no puede ser asociado a esa sesibn. La pr6xima vez, cuando su servlet invoque el metodo g e t s e s s i o n ( ) e n H t t p S e r v l e t R e q u e s t , recibiri un nuevo objeto~ttp~ession.

Demostrar el ciclo de vida de la sesion con cookies


Para familiarizarnos con el ciclo de vida de 10s objetos H t t p S e s s i o n , consideremos ahora un servlet sencillo que nos permita examinar ciertos atributos de sesibn e invalidar sesiones existentes. Tambien esaminaremos el comportamiento de este servlet en ausencia de cookies y analizaremos despues 10s modos de generar piginas Web que funcionen como deseernos, independientemente de si el navegador cliente acepta cookies o no. Llamamos a este servlet S e s s i o n L i f e c y c l e s e r v l e t . Al ser invocado, este servlet genera una pigina que muestra el estado de la sesibn, el ID de la sesi6n, la fecha y nlomento de creacibn, la Dltima vez que se accedi6 a ella y el interval0 mixin10 de inactividad. El servlet utiliza 10s rnetodos de la interfaz H t t ~ s e s s i o Dara n irn~rimir la informaci6n anterior. A ~ a r t e de esta informacibn. este servlet tambikn proporciona vinculos para recargar esta p6gina y para invalidar la sesibn actual. ~ s t es a una captura de pantalla de muestra de esta respuesta del sendet:

Session Lifecycle
Session Status.New Sess~on. Session ID: X7E38363A27 162806354C9F3F458B 192 Creation Tim-Thu Jan 04 11:26:49GMI'+OO 00 2001 Last Accessed Tune. Thu Jan 04 11:26:49 GMT+00:00 2001 M a x i m u m Inactive Interval (seconds). 300 Inrrdrfste the session
Reioad ths pqqe

Sesiones de servlets. context0 v colaboracion


Observe que la sesi6n es nueva, puesto que Cste es el primer acceso. Para ver c6mo se genera la respuesta anterior, consideremos el siguiente c6digo fuente:
/ / Importar paquetes d e Servlets import javax.servlet.Serv1etException; import javax.servlet.http.HttpServ1et; i m p o r t j avax. servlet . http. HttpSession; import javax.servlet.http.HttpServ1etRequest; i m p o r t javax.servlet.http.HttpServ1etRespor~se;
/ / Importar paquetes Java i m p o r t java. io. Printwriter; import java.io.10Exceptior~; import j a v a . util. Date;

public class SessionLifeCycleServlet extends HttpServlet protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String action = request .getparameter ("action"); if (action ! = null & & action.equals ("invalidate")) / / Invalidar la sesi6n HttpSession session = request.getsession 0 ; session. invalidate ( ) ; response. setCont.entType ("text/html") ; PrlntWriter out response.getWriter();
{

out .prir,tlr~ ("<html?"); out.println("<head><title>Session Lifecycle</title></head>"); out .println ("<bady>") ; out.printlnl"<p>Your session has been invalidated.</p>"); String 1ifeCycleURL = " / s e s s i o n / s e r v l e t / l i f e C y c 1 e e e ; out.println("<a href=\"" t 1ifeCycleUKL t "?action=newSession\">"); out.println("Create n e w sessinn</a>"); out .println ("</body></html?") ; } else ( HttpSession session = request. getsession 0 ; response. setContentType ( "text/html" ) ; Printwriter out = response.getWriter(); out .println ("<html>") ; out .println ("<meta http-equiv=\"Pragma\" content=\"no-cache\">") out.println("<head><title>Session Lifecycle</title></head>"); out.println("<body bgcolor=\"#FFFFFF\">"); o u t .println ("<hl>Session L i f e c y c l e < / c e n t e r > < / h l > " ) ;

/ / Informaci6n d e sesi6n out .print ("<br>Session Status: if (session.isNew0) ( out .println ("New Session. ' I ) ; ) else ( out .println ("Old Session. " ) ;

") ;

l
out .println ("<br>Session ID:
'I

) ;

out.println (session.getId()) ; out .println("<br>Creation Time: " ) ; out .println (new Date (session.getCreationTime ( ) ) ) ; out .println("<br>Last Accessed Time: " ) ; out .println (new Date(session.getLastAccessedTime ( ) ) ) ; out.println ( "<br>Maximum Inactive Interval (seconds):

"

) ;

Capitulo 7

String 1ifeCycleURL = "/session/servlet/lifeCyc1e~'; out .print ( " a r > < a href=\" 'I + 1ifeCycleURL + " ?action=invalidate\">") ; out .println ( I 1Invalidate the session</a></td></tr>") ; out .print ( " a r > < a href=\"" + 1ifeCycleURL + ' I \ " > " ) : out .println ("Reload this page</a>") ; out. println("</body></html>"); out. close ( ) ;

Considere las partes destacadas de este c6digo fuente. Examinemos primer0 el bloque final else.Este bloque es ejecutado cuando el servlet es invocado sin ninglin parimetro y lleva a cab0 10s siguientes pasos:
R Invoca get Session ( ) en HttpSession,con boolean true como argumento.
O Invoca get Id ( ) para obtener el I D de la sesidn. O Invoca getCreationTime ( ) para obtener la fecha y el momento de creaci6n de la sesi6n.

Puesto que este metodo devuelve la creacidn en milisegundos desde el 1 de Enero de 1970 00:00:00 GMT, necesitamos convertirlo en un objeto Date utilizando el nuevo constructor.
O Invoca getLastAccessed ( ) para obtener la fecha en que se accedi6 a la sesi6n por liltima vez. O

Invoca getMaxInact ive Inte rval ( ) para obtener la configuracih actual de interval0 miximo de inactividad.

Despues de imprimir la informaci6n anterior, el servlet tambiCn genera dos vinculos: uno para recargar la pigina y el otro para invalidar la sesidn. El primer vinculo simplemente apunta a la misma pigina. El metaetiqueta no-cache en el html generado le permite recargar la pigina haciendo clic en este vinculo. Fijese en que el segundo vinculo tiene una cadena de c o n s u l t a a c t i o n = i n v a l i d a t e adjunta. Cuando haga clic en este vinculo, el bloque i f del metodo doGet ( ) seri ejecutado. Para ver este servlet en accibn, compile este servlet y Cree el siguiente descriptor de despliegue:
< ! DOCTYPE Web-app

<?xml version="l.OV encoding="ISO-8859-l"?> PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//ENW "http://java.sun.com/j2ee/dtds/Web-app 2 3.dtdU>

<session-config> <session-timeout> < ! 5 </session-timeout> </session-config> </Web-app>

In minutes ->

Desde este momento, asumiri que sabe c6mo desplegar un componente Web en el sewidor de la Implementaci6n de Referencia J2EE y por ello s61o destacari aquellos pasos que Sean especificos de cada ejemplo. Remitase a 10s capitulos precedentes para instrucciones completas sobre el proceso.

Sesiones de servlets. contexto v colaboraci6n


Una vez que ha desplegado correctamente el servlet (utilizando una raiz de contexto de session), introduzca el U R L http://localhost:800O/session/servlet/lifeCycle en su navegador. Asegfirese d e que 10s cookies estin activados en la configuraci6n d e su navegador. La salida del navegador debe ser similar a la que mostramos al principio de este ejemplo. Veamos ahora quC ocurre si el c6digo del bloque else es ejecutado d e nuevo. Haga clic en el vinculo Reload t h i s page. La salida de su navegador debe ser similar a la que aparece a continuaci6n:

Session Lifecycle
Session Status: Old Session. Session ID 87E38363A27162806354CgF3F458B192 Creation Time: Thu Jan 04 11-26:49 GMT+00:00 2001 Last Accessed Tune: Thu Jan 04 11-26.49 GMT+OO:OO 2001 M h u m Inactive Interval (seconds)- 300 IntAdate the scssmn Feloaed this g w c

Esta vez, encontrarl que la sesi6n es antigua. El ID de la sesi6n y la fecha de creacion d e la sesi6n tan~bien siguen siendo 10s mismos. Cada vez que haga clic en el vinculo Reload this page (Volver a cargar esta plgina) lo que cambia es la ultima fecha de acceso. Esto ilustra lo sencillo que es crear y mantener un registro de las sesiones. Veamos ahora quk ocurre si hace clic en el vinculo Invalidate the session (Invalidar la sesi6n). Puesto que este U R L tiene un ( ) ser5 ejecutado para generar la pardmetro act ion=invalidate, el bloque if del m i t o d o d o ~ e t siguiente informaci6n de salida:

Capitulo 7

Prchvo

E&i
* I,

Ver

Fsvortos

Hwrarn~ertas AyvJa

+;t!i.:

OkruCIh

[& http~~)locahost:F~:!I1C1/~j~55~~:~0!.er~let/I~feC~~~le~ait11)n=1n~i~~~.f3Le 1) $Ir - . -. .~

-fa dl a~ -

@~&lm&
--

QFavwitc~

aI&-daB E

Your sesslon has been mvddated


Create new session

l~i"t& A

Ahora haga clic en el vinculo create new session (Crear nueva sesibn). La pigina resultante debe ser similar a la pantalla de entrada mostrada al principio de este ejernplo. Examine ahora el bloque if del c6digo. Este parte del servlet obtiene la sesi6n de la solicitud, invoca el mitodo invalidate ( ) y genera un nuevo vinculo de vuelta a la pigina anterior.

Ciclo de vida de sesion sin cookies


Para ver el comportamiento de sessionLifeCycleservlet sin cookies, inhabilite 10s cookies de su navegador, e invoque el URL http://localhost:800O/sessionlse1vlet/lifeCycIe. Esta vez, cuando intente recargar esta pigina, observari que la sesibn es siempre nueva, implicando que el contenedor Web no es capaz de registrar la sesi6n. C o m o hernos analizado previarnente, en casos en 10s que 10s clientes se niegan a aceptar cookies, 10s contendores Web pueden utilizar el mecanismo de reescritura de URL para registrar sesiones. Sin embargo, para que este mecanismo funcione, todos 10s URL de la pigina debe ser codificados utilizando el n s ernCtodo . adjunta una cadena de ruta rnCtodo encodeURL ( ) de la interfaz ~ t t p ~ e r v l e t ~ e s ~ o Este delaforma"; jsessionid=l23456789"alURLdeentrada. En el servlet SessionLif ecycleservlet, sustituyaarnbas lineas quecontengan:
String

liEeCyclelURL

"/ses?ion/servlet/lifeCyc1e";

por:
String l i feCycleURL =

reeponse.encodeURL("/sessi0r1~s~lrv1et/1 fi e C y c 1 e 1 ') ;

Vuelva a compilar y a desplegar el sewlet. Esta vez veri que el contenedor Web es capaz de registrar sesiones. Cuando recargue el servlet, comprobari que la sesi6n es antigua y que el URL que mostrado por su navegador es parecido a1 siguiente:

Sesiones de servlets, context0 y colaboracion

C o n la ayuda del contenedor (es decir, el mttodo encodeURL ( ) de la interfaz H t t p ervlet ~ Respons e ) , podemos ahora implementar la reescritura de URL.

Si 10s usuarios de su aplicaci6n Web activan o no cookies en sus navegadores, siempre es una buena pr5ctica codificar 10s URL como hemos mostrado anteriormente para que 10s navegadores puedan participar en las sesiones.

Metodos para gestionar el estado


Como hemos analizado a1 principio de este capitulo, otro requisito importante para construir aplicaciones Web, asi como para identificar a1 cliente, es que el servidor pueda recordar informaci6n relacionada con anteriores solicitudes/decisiones. En ttrminos sencillos, esto significa que una vez es recibida la solicitud y una vez se ha tomado una decisi6n comercial, debe ser capaz de almacenar esa informaci6n para su uso posterior. Por ejemplo, basandose en su informaci6n de registro, su solicitud bancaria online podria determinar que n o puede transferir fondos entre sus cuentas. Si la aplicaci6n es capaz de almacenar esa informacibn, no necesita volver a ejecutar la 16gica de ese proceso de toma de decisi6n cada vez que solicite una transferencia de fondos durante la sesi6n. De un mod0 similar, considere un formulario de inscripci6n online. Si el proceso de inscripcidn implica recabar una gran cantidad de datos (por ejemplo, rellenar 4 o 5 formularies), puede que no desee implementar el proceso complete con un h i c o formulario HTML. En su lugar, debe ser capaz de implementar esto en mdltiples paginas HTML (y solicitudes). Para conseguir esto, debe poder validar y almacenar informaci6n tan pronto como sea recibida del cliente. Una de las posibilidades es almacenar esta informaci6n en un almactn persistente como una base de datos relacional. Sin embargo, ?y si prefiriera realizar la actualizaci6n de la base de datos a1 final del proceso? Alternativamente, considere casos en 10s que tal information es temporal per0 es requerida durante toda la sesi6n. La interfaz Httpsession tiene funciones que cumplen este requisito. Los mttodos setAtt ribute ( ) y getAttribute ( ) de la interfaz Httpsession le permiten almacenar atributos dnicos dentro de ~t t p ess ~ ion y recuperarlos en cualquier momento antes de que expire la sesibn. Un atributo es esencialmente un objeto de lenguaje Java identificado por un nombre atributo.

public Object getAttribute (String name)

Este mttodo devuelve el atributo asociado a1 nombre especificado en esta sesi6n o null si no hay ningdn objeto asociado bajo el nombre.

public Enumeration

getAttributeNames(String

name)

Este mttodo devuelve una enumeration de 10s nombres de todos 10s atributos asociados a la sesi6n actual. Puede utilizar estos nombres con el mttodo getAttribute ( ) para recuperar 10s objetos.
El d o d o setAttribute0
public setAttribute (String name, Object attribute)

Este mttodo asocia (almacena) un objeto en la sesibn, con el nombre dado. Puede utilizar el mttodo getAtt ribut e ( ) para recuperar de nuevo el objeto. En el caso de contenedores distribuibles (examinados mas adelante), este mttodo puede lanzar una excepci6n InvalidArgumentExcept ion.

Capitulo 7
Puesto que este mktodo mantiene solo una referencia a1 atributo, necesita invocar este metodo siempre que cambie la referencia del objeto. Por ejemplo, cuando afiade un objeto H a s h t a b l e como atributo, la sesidn alberga s610 una referencia a H a s h t a b l e . Puesto que aiiadir elementos a H a s h t a b l e no afecta a la referencia a1 o b j e t o ~ a s hat b l e , necesita invocar s e t A t t r i b u t e ( ) siempre que afiada/elimine elementos de H a s h t a b l e . Sin embargo, si desea reemplazar el objeto H a s h t a b l e con otro H a s h t a b l e , necesita invocar de nuevo el metodo s e t ~ t t r i b u t i) e , pasandoel n u e v o H a s h t a b l e .
El d t o d o removeAttribute0
public void removeAttribute (String name)

Este metodo desvincula y elimina un objeto de la sesi6n con el nombre dado. Observe que 10s mitodos anteriores n o estin sincronizados. Sin embargo, es bastante posible que el mismo cliente acceda a la misma sesion en solicitudes H T T P concurrentes. P o r ejemplo, esto puede ocurrir si 10s clientes pueden producir mdltiples ventanas de navegadores (todas participando en la misma sesion). Para evitar modificaciones concurrentes de variables de sesion, considere sincronizar el acceso a estos mitodos. Multiples servlets ejecutando solicitudes pueden acceder simultineamente y modificar 10s atributos de sesi6n de un unico objeto de sesi6n a1 mismo tiempo. En el caso de que servlets de su aplicaci6n intenten manipular el mismo atributo de sesi6n, debe asegurarse de que el acceso sea sincronizado. Tambikn las aplicaciones Web pueden ser marcadas como distribuibles, en cuyo caso todos 10s atributos de sesi6n deben implementar la interfaz j a v a .l a n g . ~ e r i a l i z a b l eLa . mayoria de 10s contenedores Web comerciales ofrecen instalaciones para la distribuci6n de carga y relevo en multiples JVM. (Este proceso tambikn se conoce como clasterizaci6n.) Cuando el contenedor es distribuible, se ejecuta en multiples JVM (que pueden estar en multiples miquinas) y sus aplicaciones serin desplegadas en cada una de estas JVM. El propbsito de esta configuraci6n es permitir a1 contenedor distribuir la carga de procesamiento por estas JVM. En tales casos, el contenedor Web es libre para mover 10s objetos de sesi6n de una JVM a otra y enviar todas ]as solicitudes de cliente para esa sesion a esta JVM. Sin embargo, para que el contenedor sea capaz de intercambiar las sesiones, 10s objetos contenidos en l a ~ t t ~ s e s s i deben o n ser tambien serializables. Finalmente, incluso 10s contenedores no distribuibles pueden proporcionar persistencia de sesi6n. Considere el caso de una aplicaci6n Web con un gran numero de usuarios simultineos (y sesiones). S61o algunas de estas sesiones estarin activas, mientras que el resto no estin activas, aunque todavia no lo suficientemente inactivas para ser invalidadas (basindose en el plazo miximo de sesi6n). En tales casos, el contenedor puede elegir pasivar algunas de las sesiones menos activas en un almacenamiento persistente como el sistema de archivos, de mod0 que el contenedor pueda optimizar la memoria disponible. El contenedor podri mis tarde activar esas sesiones basindose en la actividad del usuario. Para permitir la pasivaci6n y activaci6n de sesiones, 10s atributos de la sesi6n deben ser serializables. Estas restricciones implican que debe evitar almacenar atributos no serializables, como conexiones de bases de datos y corrientes de entrada/salida, en sesiones.

Demostrar la gestion de estado


Construyamos ahora otro sencillo servlet para demostrar 10s mktodos para gestionar el estado en HttpSession:
/ / Importar paquetes de Servlets import javax.servlet.ServletException;

Sesiones de servlets. context0 v colaboracion


import import import import javax.servlet.http.HttpServ1et; javax.serv1et.http.HttpSession; javax.servlet.http.HttpServ1etRequest; javax.servlet.http.HttpServletRespor1se;

/ / Importar paquetes Java import java. io. Printwriter; import j ava . io. IOException; import java.uti1.Enumeration;
public class AttributeServlet protected void doGet extends HttpServlet

(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException (


() ;

HttpSession session = request. getsession

String name = request.getParameter("attrib name"); String value = request.getParameter("attrib value"); String remove = request .getparameter ("attrib remove") ;

(remove ! = null 6 6 remove.equals("on")) session.removeAttribute(name); 1 else [ if (name != null 6 6 name.length0 > 0 6 6 66 value. length0 > 0) [ session. setAttribute (name, value) ; 1 1 if
response. setContentType ("text/html") ; PrintWriter out = response.getWriter0;

(value != null)

out .println ("<html>") ; out.println("<meta http-equiv=\"Pragma\" content=\"no-cache\">"); out.println("<head><title>Sessior~ Attributes</title></head>"); out.println ("<body>"); out.println("<hl>Session Attributes</hl>"); out.println("Enter name and value of an attribute"); String url = response. encodeURL ("/session/servlet/attributes") ; out.println("<form action=\"" + url + " \ " method=\"GET\">"); out.println("Name: " ) ; out .println ("<input type=\"text\" out .println ("Value: " ) ; out. println ( "<input type=\"text\" SIZE=\"lO\" name=\l1attrib name\">") ; size=\"lO\" name=\"attrib value\">" ) ;

out.println("<br><input type=\"checkbox\"" + name=\"attrib remove\">Remove"); out .println ("<input type=\"submit\" name=\"update\" value=\"Update\">") out.println("</form>") ; out.println("<hr>"); out .println ("Attributes in this Session" ) ;

/ / Imprirnir todos 10s atributos d e sesi6n Enumeration e = session.getAttributeNames(); while (e.hasMoreElements 0 ) { String att-name = (String) e. nextllement 0

Capitulo 7
String att value = (String) session.getAttribute(att name);
o u t . p r i n t l n ("<br><b>Narne:<,/bb." o u t . p r i n t l n l a t t name); n u t . p r i n t l n ( " < b > V a l u e : </b>") ; out.println(att value);
n u t . p r i n t l n ( " < / b o d y > < / h t m l > " ); out.close();
) ;

Este servlet le permite introducir pares valor-nombre en una forma HTML y aiiadir estos datos a la sesi6n. Tan~bikn le permite eliminar atributos de sesi6n. Compile este servlet y afibdalo a la aplicaci6n Web que hemos creado anteriormente p a r a s e s s i o n L i f e C y c l e s e r v l e t . Alternativamente, Csta es la modificacidn del descriptor de despliegue que tendria que realizar:

Introduzca en su navegador el URL http://localhost:800O/sessioWsewletlattributes. El navegador mostrarj. un formulario para introducir el nombre y el valor de un atributo y una casilla de verificaci6n para eliminar un atributo. Aiiada cualquier par valor-nombre y pulse el bot6n Update. Encontrari una lista de atributos actuales de sesi6n presentada debajo del formulario. Esta es una salida tipica despuks de introducir algunos atributos:

Enter name and value of aa atiribute

Name:

7 Value:-]
Update

r Remove

Amibutes m tlus Session Name: Spike Value: C h p m his head Name: Buffy Value: Dead

Sesiones de servlets, context0 v colaboracion


Para elirninar cualquier atributo de la sesibn, introduzca el nornbre de un atributo en la casilla de texto Name, marque la casilla de verificacidn Remove y pulse el b o t 6 n ~ p d a t e . Esta sencillisirna aplicacion ilustra c6rno alrnacenar y recuperar atributos en el objeto H t t p s e s s i o n utilizandolosrnktodosset~ttribute( ) , g e t A t t r i b u t e ( ) , g e t A t t r i b u t e N a m e s ( ) y removeAttribute ().

Manejo de eventos de ciclo de vida de sesion


En la seccidn anterior, hernos analizado el ciclo de vida de las sesiones, que consiste en las siguientes fases:
O

Creaci6n de una nueva sesi6n Esto sucede cuando un cliente realiza por prirnera vez una solicitud H T T P a una aplicacion Web. Invalidaci6n de u n a sesi6n Esto sucede cuando la sesi6n ha expirado a causa de la inactividad, o cuando un servlet o una pigina JSP invalida explicitarnente una sesi6n.

Adernis, un contenedor puede pasivar y activar sesiones bajo las siguientes condiciones:
O

Cuando la sesi6n e s t i inactiva durante un tiernpo considerable (pero el suficiente corno para la invalidaci6n de la sesibn), el contenedor puede conservar la rnernoria escribiendo la sesi6n en un rnedio persistente corno un sisterna de archivos. Este proceso se denornina pasivaci6n; El contenedor puede reactivar la sesi6n cuando hay una solicitud procedente del cliente. Este es el proceso de activaci6n. En un contenedor distribuible, el contenedor puede transferir la sesi6n desde una JVM a otra. Esto conlleva pasivar prirnero la sesibn, transferirla despuks a travks de la conexi6n a otra JVM y luego activarla.

El API Servlet incluye rnecanisrnos de rnanejo de eventos en 10s que 10s objetos (ya sean atributos de sesi6n u otros) pueden ser notificados de lo anterior. Los siguientes son 10s escuchantes de eventos:
O

HttpSessionListener Una interfaz escuchante para notificaciones cuando se crea una nueva sesibn, o cuando una sesi6n existente es destruida ( o invalidada).
HttpSessionActivationListener Una interfaz escuchante para notificaciones cuando una sesi6n es pasivada o activada.

En arnbos casos, el contenedor encapsula el evento asociado corno un objeto H t t p S e s s i o n E v e n t . Analicernos ahora estos escuchantes y 10s eventos asociados con rnis detalle:

La interfaz HttpSessionListener
public interface HttpSessionListener

Esta interfaz tiene 10s siguientes rnktodos:


public void sessionCreated(HttpSessionEvent event)

Este rnktodo seri invocado cuando se Cree una nueva sesi6n en esta aplicaci6n Web.
public void sessionDestroyed(HttpSessionEvent event)

Capitulo 7
Este rnktodo sera invocado cuando una sesidn ya existente sea destruida (invalidada). Cualquier objeto puede irnplernentar esta interfaz para ser notificado de creacidn/invalidacidn de sesidn. Sin embargo, necesita especificar explicitarnente este objeto en el descriptor de despliegue. Por ejernplo, considere una c l a s e ~ y s e s s i o n ~t iesn e r que irnplernente esta interfaz. Para que una instancia de esta clase reciba 10s eventos anteriores, afiadiria lo siguiente al descriptor de despliegue:

Basindose en este entrada, siernpre que el contenedor crea/invalida una sesidn, notificari una instancia de M y S e s s i o n L i s t e n e r . El contenedor crea instancias de todos 10s escuchantes en el arranque del contenedor o antes de crear cualquier sesidn. ? C u d es el objetivo de este escuchante? La principal aplicacidn de este escuchante es realizar cualquier accidn necesaria antes de que una sesidn sea creada o destruida. Por ejernplo, puede realizar llarnadas a sus sisternas en segundo plano para ejecutar acciones de ernpresa cuando se crea una nueva sesidn.

La interfaz HttpSessionActivationListener
public interface HttpSessionActivationListener

Esta interfaz puede ser utilizada para notificacidn de activacidn o pasivacidn. Esta interfaz tiene 10s siguientes rnktodos:
El d t o d o sessionDidActivate0
public void sessionDidActivate(HttpSessionEvent event)

El contenedor invoca este rnktodo despuks de activar una sesidn.


El d o d o seosionWillPassivate()
public void

sessionWillPassivate(HttpSessionEvent

event)

El contenedor invoca este rnktodo antes de pasivar una sesidn existente. Los atributos asociados a sesiones pueden irnplernentar esta interfaz. Cuando un atributo es asociado a una sesidn, el contenedor invoca 10s rnetodos anteriores despuks de pasivar y antes de activar sesiones. Puesto que esta interfaz pretende irnplernentar atributos, no hay una entrada necesaria en el descriptor de despliegue. Una de las situaciones en las que este evento colabora es aquella en la que un atributo alberga referencias a objetos rernotos corno EJB o incluso objetos no serializables. En este caso, el atributo puede volver a crear esas referencias cuando el evento s e s s i o n D i d A c t i v a t e ( ) sea invocado.

La clase HttpSessionEvent
public class HttpSessionEvent extends java.util.EventObject

~ s t es e el evento para arnbos escuchantes analizados anteriorrnente. Esta clase tiene un Gnico rnktodo.
El d t o d o getSesrion0
public HttpSession getsession
()

C o n este rnktodo, el escuchador puede acceder a la sesidn HTTP y sus contenidos.

Sesiones de servlets, context0 y colaboracion

Manejo de eventos de atributos de sesion


Ademis de 10s anteriores, existen dos escuchantes mis para controlar el estado (atributos) de las sesiones. Estos escuchador estin basados en las siguientes actividades:

O Ariadir un atributo a una sesi6n O Reemplazar un atributo en una sesi6n por otro objeto
0

Eliminar un atributo de una sesi6n

Tanto 10s atributos que participan en estas acciones como otros objetos pueden escuchar estos eventos. Las siguientes son las interfaces destinadas a manejar estos eventos:

La interfaz HttpSessionBindingListener
public interface HttpSessionBindingListener extends java.util.EventListener

Esta interfaz puede utilizarse para notificar un objeto cuando esti siendo situado en la sesi6n (utilizando el metodo s e t A t t r i b u t e ( ) ), o eliminado de la sesi6n (via metodo r e m o v e A t t r i b u t e ( ) ).

El d t o d o valueBound0
public void valueBound(HttpSessionBindingEvent event)

El contenedor invoca este mitodo en el objeto que esti siendo vinculado de una sesibn.

El d o d o valueUnbound0
public void valueUnbound(HttpSessionBindingEvent event)

El contenedor invoca este metodo en el objeto que esti siendo desvinculado de una sesi6n. La desvinculaci6n puede tener lugar eliminindolo explicitamente de la sesibn, o durante la invalidaci6n de la sesi6n. Cuando el atributo que i m p l e m e n t a ~ t t p s es si o n B i n d i n g L i s t e n e r es afiadido a H t t p ~ e s s i o n , e l contenedor Web notifica el atributo que esti siendo vinculado a la sesi6n. De un mod0 similar, cuando el atributo es eliminado de la sesibn, el contenedor Web notifica al atributo que esti siendo desvinculado de la sesi6n. El atributo puede utilizar 10s mktodos de retrollamada proporcionados para inicializar o limpiar su estado. Por ejemplo, en una aplicacidn de carro de la compra, considere el atributo de carro de la compra almacenado en la sesi6n. Este objeto sera creado cuando el comprador visite por primera vez el sitio. Asumamos que el comprador ha afiadido articulos a1 carro pero, en lugar de pasar por caja, decide no continuar y abandona el sitio. Mis tarde, cuando expira la sesion del usuario, el contenedor notifica al atributo del carro de la compra que esti siendo desvinculado de la sesi6n. El objeto del carro puede guardar el carro de la compra en una base de datos. Cuando el mismo usuario vuelve a visitar el sitio, la aplicaci6n vincula el atributo de carro de la compra a la sesi6n de nuevo. Esta vez, el atributo de carro de la compra puede recargar el carro de la compra guardado y proporcionar una experiencia de usuario ininterrumpida para el comprador.
Fijese en que, para que el atributo del carro de la compra implemente estas tareas, puede necesitar acceder a la ~t t p s e s s i o n a la que esta'asociado. C o m o verd despue's, el evento l a ~t t psession Ht tp~essionBindingEventproporcionaaccesoa

La interfaz HttpSessionAttributeListener
public interface HttpSessionAttributeListener extends java.util.EventListener

Esta interfaz es similar a la i n t e r f a z ~ t t p s e s s i o n ~ i n d i n ~ e~ ne is rt except0 que esta destinada a ser irnplementada y notificada cuando el estado de una sesidn cambia. Esta interfaz tiene 10s siguientes rnitodos:
El &todo attributeAdded0
public void attributeAdded(HttpSessionBindingEvent event)

El contenedor invoca este mitodo cuando un atributo es ahadido a una sesidn.


El d t o d o attributeRemoved0
public void attributeRemoved(HttpSessionBindingEvent event)

El metodo invoca este rnetodo cuando un atributo es elirninado de una sesion.


El metodo attributeReplaced0
public void

attributeReplaced(HttpSessionBindingEvent

event)

El contenedor invoca este metodo cuando un atributo es reernplazado por otro. Esto puede suceder, por ejernplo, cuando invoque el rnetodo s e t A t t r i b u t e ( ) en la sesidn con el rnisrno nornbre per0 con diferentes valor.

La clase HttpSessionBindingEvent
public class HttpSessionBindingListener extends HttpSessionEvent

Esta clase representa 10s eventos de vinculacidn y desvinculacidn de sesidn y tiene 10s siguientes rnktodos:
El d t o d o getNameO
public String getName 0

Este metodo devuelve el nornbre de un atributo que ha sido utilizado el vincular/desvincular el atributo en la sesi6n.
El d t o d o getvalue0
public Object getvalue ( )

Este metodo devuelve el valor de un atributo que esti siendo vinculado, desvinculado, o reernplazado.
El d t o d o getSession0
public HttpSession getsession()

Este metodo devuelve un o b j e t o ~ t t p s e s s i o n del que el atributo esti siendo vinculado/desvinculado o reernplazado.

Un sencillo carro de la compra utilizando sesiones


En esta seccidn considerarernos una sencilla aplicaci6n de carro de la cornpra, para ilustrar varios conceptos asociados a1 registro de sesiones. Tales aplicaciones perrniten habitualrnente a un usuario seleccionar articulos de un catilogo y situarlos en un carro de la cornpre virtual, antes de proceder a pasar por caja-y pagar 10s articulos.

Sesiones de servlets, context0 y colaboracion


Esta aplicaci6n de carro de la compra tiene dos servlets: uno para generar un catilogo y el otro para aiiadir articulos a un carro y mostrar 10s contenidos del carro. En esta aplicacion, utilizaremos el mismo grupo de m i t o d o H t t p s e s s i o n que utilizamos e n f i t t r i b u t e s e r v l e t Sin embargo, el objetivo del carro dela compra es demostrar c6mo estos mitodos pueden ser combinados para construir aplicaciones en la vida real. Aqui consideraremos una implementaci6n muy limitada sin la mayoria de las caracteristicas que esperaria en un carro de la compra completamente funcional. Le animamos a aiiadir mis funcionalidad a esta aplicaci6n mientras explora el API Java Servlet.

El servlet del catalog0


El catilogo consiste en dos partes. La primera parte es una instrucci6n que muestra el numero actual de libros seleccionados en el carro de la compra y la segunda es una formulario HTML, con la lista de libros presentada en un grupo de casillas de verificaci6n. El formulario HTML consiste en una pequeiia lista de articulos presentados en una tabla. Cada articulo tiene una casilla de verificaci6n a1 lado para que el usuario seleccione el articulo y lo aiiada a su carro de la compra. En un tipico programa de carro de la compra, las piginas del catilogo son generadas desde una base de datos pero, para nuestro ejemplo, utilizamos una lista estitica como demostraci6n:
/ / Importar paquetes d e servlet import javax.servlet.Serv1etException; import javax.servlet.http.~'ttpServlet; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpServletRequest; i m p o r t javax.servlet.http.HttpServ1etRespor~se;
//

Importar paquetes java import java. io. Frir~tWriter; import java.io.IOException; import java.util.ArrayList;

public class Catalog exterlds HttpServlet { protected v ~ l ddoGet(HttpServ1etRequest req, HttpServletResponse throws ServletException, IOException { HttpSession session = req.getSession( ) ; int itemcount = 0; ArrayList cart = (ArrayList) session.getAttribute ("carttt1; if (cart ! = null) { itemcount = cart. size ( ) ;
1

res)

res. setContentType ( " t e x t / h t m l V ; Printwriter out = res.getWriter0; out.println("<html><head><title>Simple Shopping Cart " + "Example</title></head>"l; out.println("<body><table border=\"O\" width=\"lOO%\"><tr>"); out .println ("<td valign=\"top\"><img " + "src=\"/cart/images/logo.gif\"></td>") ; out .println ("<td align=\"left\" valign=\"bottom\">") ; out.println("<hl>WROX Book Store</hl></td></tr></table><hr>"); out .println ("<p>You've " + itemCount + " items in your cart. </p>" ) out .print ("<form action=\"") ; o u t .println ( r e s .encodeURL("/cart/servlet/cart") 1 ; out.println ( " \ " method=\"post\">") ; o u t .println ("<table cellspacing=\"5\" cellpaddir~g=\"5\"><tr>") ; out.prir~tlr~("<td align=\"center\"><b>Add t o Cart</b></td>");

Capitulo 7
out .println ( " < t d a l i g n = \ " c e r ~ t e r \ " > < / t d > < / t r > < t r >; ") o u t .println ("<td align=\"center\">") ; out .println ("<input type=\"Checkbox\" name=\"item\"" t " value=\"Begining Java2 - JDK 1.4 Version\"></td>"); out.println("<td align=\"left\">Itern 1: " t " Begining Java2 - JDK 1.4 Version</td></tr><tr>"i; out .println ("<td align=\"center\">") ; out.println("<input type=\"Checkbox\" narne=\"item\"" t " value=\"Professional Java XML\"></td>") ; out .println ("<td align=\"left\">Itern 2: " t " Professional Java XML</td></tr><tr>" ) ; out .println ("<td align=\"center\">") ; out .println ("<input type=\"Checkbox\" narne=\"item\"" + " value=\" Professional Java Server Prograrnming\"></td>" ) out .println ("<td align=\"left\">Item 3: Professional Java " t "Server P r o q r a r n m i n g < / t d > < / t r > " i ; out. println ( "</table><hr>") ; out.println("<input type=\"Subrnit\" name=\"btn submit\" " t "value=\"Add to Cart\">" ) ; out .prir~tlr~("</forrn></body></htrnl>") ; out. close (
) ;

I
1

Este sewlet obtiene el numero de libros a partir de 10s datos almacenados en la H t t p S e s s i o n . Comienza para e s tobtener la sesi6n actual: utilizando el mktodo g e t s e s s i o n ( ) en el o b j e t o ~ t t p ~ e r v l e t ~ e q u
HttpSession cession
=

req.getSession i 1 ;

~ s t es e el primer paso requerido para crear y registrar sesiones HTTP. Tambikn encontrari una llamada similarreg. g e t s e s s i o n 0 e n e l s e w l e t s h o p p i n g ~ a r t . Utiliza entonces un a t r i b u t o w c a r t " H t t p S e s s i o n para encontrar y mostrar el numero de libros en el carro. C o m o veremos en un momento, el senlet S h o p p i n g C a r t almacena y actualiza este atributo cuando 10s articulos son afiadidos a1 carro, utilizando un objeto A r r a y l i s t para almacenar la lista de libros seleccionados.
ArrayList cart
=

(ArrayListj

session.getAttribute ("cart"j

El resto de este senlet prepara el catdogo. ~ s t genera e un formulario con una acci6n POST, que envia la lista de libros seleccionados en la solicitud HTTP.

El servlet ShoppingCart
El sewlet S h o p p i n g C a r t es responsable de afiadir articulos a1 carro. Este sewlet toma (de la solicitud POST presentada por el servlet c a t a l o g ) la lista de libros seleccionados y actualiza el carro de la compra. ti s En esta aplicacion limitada, el carro de la compra es modelado como un objeto j a v a .u t i l ~ r r a y ~ que alberga 10s nombres de 10s articulos. Este objeto es entonces almacenado como un atributo con el nombre " c a r t " e n l a ~ t t p ~ e s s i o n :

/ / Irnportar paquetes d e servlets import javax.servlet.ServletExceptior~; import javax.servlet.http.HttpServlet; import javax.serv1et.http.HttpSession; import javax.servlet.http.HttpServ1etRequest; import javax.servlet.http.HttpServ1etResponse;

//

Irnportar paquetes

java

import import import import

java. io. Printwriter; j ava. io. IOException; java.util.ArrayList; java.util.1terator; extends HttpServlet

public class ShoppingCart public void doPost

I
res)

(HttpServletRequest req, HttpServletResponse throws ServletException, IOExceptlon ( HttpSession session = req.getSession(true); ArrayList cart
=

(ArrayList) session.getAttribute ("cart");

if (cart == null) 1 cart = new A r r a y ~ i s t ( ) ; session.setAttribute ("cart", Cart) ;

1
Printwriter out = res.getWriter(); ; res .setContentType ("text/htmll') String [ I itemsselected; String itemName; itemsselected = req.getParameterValues ("item"); if (itemsselected ! = null) { for (int i = 0 ; i < itemsSelected.length; i++) [ itemName itemsSelected[i] ; cart. add (itemName);

1 1
/ / Imprimir contenidos actuales del carro out.println("<html><head><title>"); out .println ("Shopping Cart Contents") ; out .println("</title></head>") ; out .println ("<body>") ; o u t .println ("<hl>Items currently in your cart</hl>") ; out.println("<hr>");
Iterator iterator = cart. iterator ( ) ; while (iterator.hasNext ( ) ) { out .println ("<p>" + iterator.next ( )
1

"</p>");

out.print("<hr><p><a href=\""); out.print(res.encodeURL("/cart/servlet/catalog")1 ; out .println("\">Back to the shop</a></p>");

Recuerda que cuando un formulario contiene mliltiples casillas de verificaci6n con el mismo nombre, el ( )s es utilizado parimetro puede tener mliltiples valores. Por lo tanto, el mCtodo get ~ a r a m e t e r ~ a l u e para extraer 10s libros seleccionados de la solicitud. Finalmente, generamos una pigina que contenga 10s contenidos actuales del carro de la compra y la vinculamos de vuelta a1 carro. Compile estos dos archivos Java y Cree el siguiente descriptor de despliegue:

Capitulo 7
<?xrnl version="l.O" e n c o d i n g = " I S O - 0 8 5 9 - l " ? > I! EOCTY P E W e b - a p p P U B L I C "-//Sun M i c r o s y s t e r n s , Inc.//DTD Web A p p l i c a t i o n 2 . 3 / / E N n ' "http://java.sun.corn/j2ee/dtds/tIeb-app 2 3.dtdM?

Cuando haya desplegado la aplicacion, utilizando una raiz context0 de cart, abra un navegador en http:ll loca Ihost:8000/ca rVservlet/catalog. Las capturas de pantalla que aparecen a continuaci6n muestran el catilogo y el carro de la cornpra. El catilogo tiene solo tres entrada y es generado utilizando el servlet c a t L l d g :

WROX Book Store

Add t o Cart

r r r

Item 1 Be-

Java2 - JDK 1.4 Vers~on

Item 2.Professional Java XML Item 3 Professional Java Server Progarnrmng

Para nfiadir articulos al carro, marque las casillas situadas al lado del articulo y pulse el b o t h ~ d t do C a r t (Agregar al carro). Esto provocari que el servlet S h o p p i n g c a r t genere la pantalla de carro de la cornpra:

376

Sesiones de servlets, contexto y colaboracion

Items currently in your cart


Begring Java2 - JDK 1 4 Version

Professional Java XML

Back to the shop

Context0 de servlet
En el API lava Servlet. el contexto de servlet define la vista de un servlet de la a~licaci6n Web v proporciona acceso a recursos e instalaciones (con10 registro) comunes a todos 10s servlets de la aplicaci6n. A diferencia de una sesion, que especifica de un cliente, el contexto de servlet es especifico de una aplicacion Web particular ejecutada en una JVM. Es decir, cada aplicaci6n Web de un contenedor tendri un h i c o contexto de servlet asociado a el. El contexto de servlet es con todo un concept0 litil proporcionado por el API Servlet. En la secci6n anterior, hemos visto corn0 podemos utilizar 10s objetos HttpSession para mantener el testado relacionado a un dnico cliente del servidor. El contexto de servidor complementa esta funci6n permitiindole mantener el estado en el nivel de la aplicacion, es decir, la informaci6n de estado comlin a todos 10s senlets y clientes de la aplicaci6n. El API Java Servlet proporciona una interfaz servletcontext para representar un contexto: 10s recursos compartidos por un grupo de servlets. Las versiones 1.0 y 2.0 del API Servlet, la interfaz ~ervlet~ontex s61o t otorgaba acceso a informaci6n sobre el entorno del servlet, como el nombre del servidor, las representaciones de tipo MIME, etc., y un metodo log ( ) para escribir mensajes de registro a1 archivo de registro del servidor. La mayoria de las implementaciones proporcionaban un contexto de servlet para todos 10s servlets dentro de un host, o uno por cada host virtual. Desde la version 2.1 del API, la funci6n de la interfaz servletcontext ha sido revisada para representar el entorno para cada aplicaci6n Web y para actuar como un repositorio compartido de atributos para todos 10s servlets de la aplicaci6n. La interfaz permite a 10s servlets del mismo contexto compartir informaci6n por atributos de contexto, de un mod0 similar a 10s atributos de sesidn que ya hemos visto.

Capitulo 7
Cada contexto de semlet esti grabado en una ruta especifica en el semidor Web. En 10s ejemplos que hemos visto hasta ahora, hemos tenido que especificar una raiz de contexto durante el proceso de despliegue. Por ejemplo, la aplicaci6n T e c h S u p p o r t del capitulo anterior esti asociada a un contexto / t e c h S u p p o r t . C o n la ayuda de esta noci6n,.puede desplegar multiples aplicaciones Web bajo diferentes nombres de raiz de contexto. Todas estas apl~caciones pueden coexistir como si estuvieran desplegadas en diferentes contenedores. Examinemos la interfaz s e r v l e t c o n t e x t .

La interfaz ServletContext
public interface ServletContext

La interfaz S e r v l e t c o n t e x t encapsula la nocion de un contexto para una aplicaci6n Web. un objeto de este tip0 puedeserobtenidoutilizandoelm~todoget~erv~et~ontext ( ) d e l o b j e t o ~ t t p s e r v l e tH . ttpservlet a su vez obtiene este objeto del objeto s e r v l e t c o n f i g que le fue pasado durante la inicializaci6n.
La interfaz ~ e r v l e t ~ o n t e especifica xt 10s siguientes mitodos; 10s contenedores Web proporcionan una implernentacion de la interfaz:
public public public public public public public public public public public public public public public public public public publ i c publ i c String getMimeType (String fileName) URL getResource (String path) Inputstream getResourceAsStream(String path) RequestDispatcher getRequestDispatcher(String path) RequestDispatcher getNamedDispatcher(String name) String getRealPath (String path) ServletContext getContext(String uriPath) String getServerInfo ( ) String getServletContextName() Set getResourcePaths (String path) String getInitParameter(String name) Enumeration getInitParameterNames0 Object getAttribute (String name) Enumeration getAttributeNames 0 void setAttribute (String name, Object attribute) void removeAttribute (String name) int getMa jorversion ( ) int getninorversion ( ) void log(String message) void log (String message, Throwable cause)

El d t o d o getMimeType0
public String getMimeType(String fileName)

Este metodo devuelve el tipo MIME de un archivo por su extensi6n. Puede especificar 10s tipos MIME que su aplicaci6n puede manejar en el descriptor de despliegue.

El d t o d o getResource0
public URL getResource (String path)

Este d t o d o devuelve el URL a un recurso en la ruta especificada y puede utilizarse para construir objetos URL para archivos del sistema local de archivos.

El d t o d o getResourceAsStreamO
public Inputstream getResourceAsStream(String path)

Sesiones de servlets, contexto y colaboracion


Este metodo es similar a g e tRes ource ( ) ,excepto en que devuelve una corriente de entrada asociada a1 URL. El d t o d o getRequestDispatcher0
public RequestDispatcher

getRequestDispatcher(String path)

Este metodo devuelve un objeto RequestDispatche r asociado a1 recurso situado en la ruta actual. Puede utilizar el RequestDispatcher para delegar el procesamiento de solicitud/respuesta a otros recursos dentro de la aplicaci6n (analizaremos el RequestDispatcher con mis detalles mis adelante en este capitulo). El d t o d o getNamedDispatcher0
public ~ e q u e s t D i s p a t c h e r getNamedDispatcher(String path)

Este metodo es similar a1 metodo getRequestDispatcher ( ) ,excepto que este metodo aceptalos nombres de alias asignados a clases de servlet en el descriptor de despliegue. El d o d o getRealPath0
public String getRealPath (String path)

En una aplicaci6n Web, 10s recursos son referidos mediante rutas relativas a la ruta que apunta a1 contexto, por lo que este metodo le permite obtener la ruta real (en el sistema de archivos del servidor) de la ruta relativa a1 contexto. El d o d o getcontext0
public ServletContext getContext(String uriPath)

Este metodo devuelve un objeto servletcontext asociado a1 URL especificado en el servidor. Sin embargo, debido a posibles limitaciones de seguridad impuestas por el contenedor Web, este metodo puede devolver null,ya que este metodo, de no ser asi, le permite acceder a objetos de contexto que pertenecen a otras aplicaciones Web. El d t o d o getSewerlnfo0
public String getServerInfo
()

Este metodo devuelve el nombre y la versi6n del contenedor de servlet en el que se esti ejecutando el servlet. Esta informaci6n puede utilizarse con prop6sitos de registro. El d t o d o getSewletContextName0
public String g e t S e r v l e t C o n t e x t N a r n e ( )

Este metodo devuelve el nombre de presentaci6n de la aplicaci6n Web. A cada aplicaci6n se le puede asignar un nombre de presentaci6n en el descriptor de despliegue afiadiendo un elemento <displayname>. Este metodo devuelve este nombre. Este metodo devuelve null si falta este elemento en el descriptor de despliegue. El d t o d o getResourcePaths0
public Set getResourcePaths(String path)

Este metodo es funcionalmente similar a ejecutar un comando de listado de directorio. Dado un nombre de ruta relativo a la raiz de la aplicaci6n Web, este metodo devuelve todas las sub-rutas.

Capitulo 7
Los mirtodos getlnitParameter0y getlnitParameterNames0
public String getInitParameter(Strin9 name) public Enumeration getInitParameterNames0

C o m o o y r r e con 10s servlets, podemos especificar 10s parimetros de inicializacidn para contextos de servlet. Estos pueden ser especificados en el descriptor de despliegue utilizando etiquetas <cont ext param>. C o n la ayuda de 10s dos metodos anteriores, puede acceder a estos parirnetros.

Los m(rtodos getAttribute0, getAttributeNam-0,

setAttributes0 y removeAttribute0

public Object getAttribute (String name) public Enumeration getAttributeNames 0 public void setAttribute (String name, Object public void removeAttribute (String name)

attribute)

Estos cuatro mktodos le perrniten mantener el estado de una aplicaci6n Web. Cualquier servlet puede configurar un atributo, que puede ser entonces obtenido por cualquier otro servlet dentro de la rnisrna aplicaci6n, con independencia de que estos senlets estin sirviendo a1 misrno cliente o no. Utilizando estos mktodos, 10s servlets pueden compartir informaci6n comGn a todos 10s servlets.

Los d o d o s logo
public void log( java.lang. String msg) public void log(String message, Throwable throwable)

La interfaz S e r v l e t c o n t ext proporciona dos mktodos con prop6sitos de registro. De estos, el segundo metodo puede ser utilizado para excepciones de registro, mientras que el primer0 puede utilizarse con prop6sitos generales de registro.

El manejo de eventos de ciclo de vida de ServletContext


El contenedor crea el contexto de servlet antes de intentar servir cualquier contenido de una aplicacidn Web. De un modo similar, el contenedor puede eliminar el contexto antes de dejar de servir 10s contenidos de una aplicaci6n Web. Para manejar estos dos eventos, el API Servlet especifica la siguiente interfaz:

La interfaz ServletContextListener
public interface ServletContextListener extends java.util.EventListener

U n objeto de esta interfaz recibe eventos sobre la creacidn o destruccidn de un contexto de servlet. Esta interfaz tiene 10s siguientes mktodos:
public void contextInitialized(ServletContextEvent event)

Este mktodo seri invocado cuando se Cree un nuevo contexto.


public void contextDestroyed(Serv1etContextEvent event)

Este mktodo seri invocado cuando se destruya un contexto ya existente. Puede registrar una clase que irnplernente esta interfaz utilizando el elernento < 1 i st ener> en el descriptor de despliegue:

Sesiones de servlets, contexto y colaboraci6n

Observe que este es el mismo elemento que tambien podemos utilizar para especificar clases que implementen la i n t e r f a z ~ t t ~ s eisosn L i s t e n e r .

ServletContextAttributeListener
public interface ServletContextAttributeListener extends java.uti1.EventListener

Esta interfaz es similar aHttpSessionAttributeListener y es notificada cuando hay un cambio en el estado de un contexto. Esta interfaz tiene 10s siguientes mktodos:
public void attributeAdded(Serv1etContextAttributeEvent event)

El contenedor invoca este metodo en el escuchante cuando un nuevo atributo es aiiadido a1 contexto.
public void attributeReplaced(ServletContextAttributeEvent event)

El contenedor invoca este metodo en el escuchante cuando el valor de un atributo es alterado per0 el atributo mismo. Esto sucede cuando invocamos el metodo s e t A t t r i b u t e ( ) en el contexto con el nombre de un atributo aiiadido anteriormente como nombre.
public void attributeRernoved(Serv1etContextAttributeEvent event)

El contenedor invoca este metodo en el escuchante cuando un atributo es eliminado del contexto.

Una aplicacion de chat que utiliza contexto y sesiones


Para ilustrar tanto la sesi6n como el contexto en acci6n, consideremos ahora una aplicaci6n de chat multisala para catear en la red. Utilizando esta aplicaci6n, dos o mis usuarios pueden entrar en una sala de chat y enviar mensajes. Otros usuarios que participen en la misma sala de chat reciben esos mensajes. En esta situacibn, cualquier usuario puede enviar un mensaje en cualquier momento y cuando el usuario envia un mensaje, todos 10s usuarios participantes de la sala reciben el mensaje. iQuk supone construir una aplicacibn de chat? Para este ejercicio, consideremos un chat con base de navegador (es decir, todos 10s clientes son navegadores). Para apoyar a tales clientes, tambien necesitamos una aplicaci6n Web. Cada cliente conectar con esta aplicaci6n para chatear, como se nluestra a continuaci6n:

Esta configuraci6n es similar a la de cualquier aplicaci6n Web tipica. A partir de ella, puede identificar 10s siguientes requisitos inmediatos para esta aplicaci6n:
0 0

El servidor debe proporcionar alguna interfaz (como un formulario HTML) para enviar mensajes El cliente debe conectar peri6dicamente con el servidor y descargar mensajes nuevos

Aunque s61o aparece un cliente en esta figura, para que un chat tenga lugar necesita dos o mis clientes, interactuando simultineamente con el servidor que alberga la aplicaci6n. Puesto que todos 10s usuarios para una determinada sala de chat ven 10s mismo mensajes, debe existir un mecanismo para compartir esos datos. Tenemos, por lo tanto, otro requisito:

O El servidor debe mantener mensajes enviados a una sala de chat y permitir a todos 10s usuarios
descargar 10s mensajes Ademis estos requisitos, para que multiples usuarios chateen sobre diferentes temas, tambikn necesitamos una funci6n para mantener multiples salas de chat, lo que supone 10s siguientes requisitos adicionales:
0 El servidor debe facilitar la gesti6n de multiples salas de chat. U n o debe ser capaz de crear salas de

chat a medida que sean requeridas y eliminar una sala de chat cuando ya no sea requerida.
0

El servidor tambiin debe proporcionar un medio para identificar a cada usuario en una determinada sala de chat. Es decir, cada cliente debe proporcionar un nombre antes de entrar en una sala de chat.

De estos requisitos, la necesidad de multiples salas de chat y la interacci6n simultinea entre usuarios que comparten datos, son 10s que hacen que esta aplicacion sea un reto. Configuremos y construyamos ahora esta aplicaci6n. El objetivo de este ejercicio es ilustrar c6mo utilizar el API Servlet para construir una aplicaci6n de este tipo. Antes de proceder con la construcci6n de esta aplicaci6n, examinemos primero ciertos requisitos de modelado:
0 0

La aplicaci6n de chat consiste en multiples salas de chat. Cualquier usuario puede abandonar una sala de chat y entrar en otra. En una determinada sala de chat, habri mis de un usuario intercambiando mensajes.

Para construir una aplicaci6n de este tipo, necesitamos modelar ciertas clases:
O

Una clase ChatRoompara representar una sala de chat. Puesto que una sala de chat es compartida por multiples usuarios (y, por lo tanto, mhltiples sesiones), el s e r v l e t c o n t e x t es el lugar id6neo para almacenar ~ h a t ~ o o Como m puede haber mas de una sala de chat, necesitamos mantener una lista de ChatRooms en el s e r v l e t c o n t e x t . Una C h a t E n t r y para representar un mensaje de chat. En una sala de chat, se intercambian multiples mensajes entre usuarios. Una entrada de chat es n e lista de objetos C h a t E n t r y . parte de una sala de chat y la clase ~ h a t ~ o o m m a n t i e una

El diagrama que presentamos a continuaci6n muestra un anilisis de las relaciones entre estas clases:

Sesiones de servlets, context0 y colaboracion

lnterfaz
Se~letContext

Sala de chat

Entrada de chat

La clase j a v a .u t i l .HashMap es utilizadapara albergar o b j e t o s ~ h a t ~ o o m cada y objeto~hat~oom contiene una pila de objetos C h a t E n t r y . El objeto HashMap es el punto de entrada para todos 10s otros objetos, por lo que una referenciaal objetoHashMap es alrnacenada corno un atributo s e r v l e t c o n t e x t bajo el nornbre de r o o m L i s t. Los objetos HashMap, ChatRoom y ~ h a t ~ n tjuntos r y representan el estado de la aplicacion de chat. Estas clases representan el rnodelo de datos para esta aplicaci6n. Analicernos ahora la interacci6n de 10s usuarios de chat con el servidor:
0

Gestibn de la sala Necesitarnos un servlet para crear y eliminar salas de chat. Llarnernos a1 servlet C h a t A d m i n S e r v l e t . Unirse a u n chat Una vez se ha creado un grupo de salas de chat, necesitarnos proporcionar a1 usuario del chat las salas disponibles, pedirle a1 usuario que se identifique y dejarle entrar en una sala de chat. Designernos un servlet L i s t R o o m s S e r v l e t para gestionar estas tareas.

C I

Chat El liltirno paso es el chat en si rnisrno. Para esta tarea, necesitarnos proporcionar un rnedio para enviar un rnensaje y otro rnedio para la descarga de rnensajes de chat. Designernos un C h a t R o o m S e r v l e t para estas tareas.

Estos tres senlets son tambikn responsables de proporcionar cualquier contenido dinamico (como una lista de salas de chat disponibles, mensajes de chat, etc.).

Una vez haya leido el capitulo sobre JSP y haya aprendido a utilizar las priginas JSP para ofrecer contenido dinrimico, puede volver a esta apficacidn y recrearla para utilizar priginas JSP en combinacidn con 10s serulets anteriores.
Consideremos ahora la implementaci6n de las clases anteriores.

La clase ChatRoom
Una instancia de la clase ChatRoomrepresenta una sala individual de chat y cada instancia mantiene todos 10s mensajes para una sala especifica:
import
j ava . u t i l . S t a c k ;

p u b l i c c l a s s ChatRoom e x t e n d s p r i v a t e S t r i r ~ g name; private String description;

Stack

p u b l i c C h a t R o o m ( S t r i n g name, S t r i n g d e s c r i p t i o n ) t h i s . n a m e = name; this.description = description;

I
public void addChatEntry(ChatEntry e n t r y ) p u s h ( e n t r y );
{

I
public String getDescription ( return description;
{

p u b l i c S t r i n g getName() r e t u r n name;

Esta clase amplia j a v a .u t i l . S t a c k . Cada ChatRoom tiene un nombre y una description. Estos valores con pasados a1 constructor cuando se crea la sala. Cuando un usuario introduce un mensaje chat, el metodo a d d C h a t E n t r y ( ) es utiliza para ahadir el mensaje a la sala. Aunque esta clase puede parecer sencilla, hay ciertas razones por las que hemos disehado esta clase de este modo. En primer lugar, mfiltiples clientes accedeh a una C h a t Roomy ahaden mensajes. Para asegurarnos que el C h a t Room esti a salvo de hilos, necesitamos sincronizar el acceso a 10s metodos que ahaden/ eliminan mensajes del C h a t R o o n Sin embargo, no estamos realizando aqui esa tarea porque la clase j a v a .u t l l . S t a c k , que amplia j a v a .u t i l . V e c t o r , esti sincronizada. Los mktodos que ahaden y eliminan elementos en un vector son implementados de un mod0 libre de hilos.

La clase ChatEntry
U n objeto C h a t E n t r y representa un mensaje en una sala de chat:
public c l a s s ChatEntry 1 p r i v a t e S t r i r ~ gp r o f i l e N a m e ; p r i v a t e S t r i n q message;

Sesiones de servlets, context0 y colaboracion


p u b l i c ChatEntry ( S t r i n g profileName, this.profileName = profileName; t h i s . m e s s a g e = message;
S t r i n g message)
(

I
p u b l i c S t r i n g getProfileNarne ( ) r e t u r n profileNarne;
{

I
p u b l i c S t r i n g getMessage l ) return message;

U n a ChatEntry contiene un mensaje de chat y el nombre del usuario (profileName) que envia el mensaje.

El servlet de adrninistracion
ChatAdminServlet proporciona funciones d e administraci6n para la aplicaci6n chat. Este servlet implementa 10s m i t o d o s doGet ( ) y dopost ( ) . El m i t o d o doGet ( ) s e r i invocado cuando invoque directamente el servlet y el m i t o d o dopost ( ) cuando elimine o aiiada salas d e chat.

La respuesta de este servlet a1 ser invocado p o r primera vez se muestra a continuaci6n; con esta interfaz de usuario, puede aiiadir nuevas salas de chat:

Archvo

Eciici6n

Ver

Fawitos

Huremientas

Ayude

I Chat room administration


I
Enter a new room and the descnpbon Name
I~ewa sewlet chat

Descnpbon.

Chat Now

Este servlet necesita implementar:

O U n m i t o d o doGet

( ) para generar una lista de salas d e chat existentes (si hay alguna), seguida por un formulario para crear una sala d e chat.

385

Capitulo 7
0

U n metodo d o p o s t ( ) para procesar la respuesta generada por el envio del formulario. El procesamiento implica crear una nueva sala de chat, o eliminar una sala ya existente.

En todos 10s servlets de es,te ejemplo, utilizamos tres parimetros de context0 especificados en el LISTROOM-PATH ~ADMIN-PATH. Como veri descriptor de despliegue. Estos son: CHATROOM-PATH, mis adelantes en el descriptor de despliegue. Estos parimetros apuntan a 10s URL del ~ h a t ~ o o m ~ e r v l e t , ~ i s t ~ o o m s ~y e~ rv hl ae tt ~dmin~erv respectivamente: let
/ / Importar paquetes d e servlet import javax.servlet.Serv1etException; import j avax. servlet .UriavailableException; import javax.servlet.Serv1etContext; import javax.servlet.http.HttpServ1et; import javax.servlet.http.HttpServ1etRequest; import javax.servlet.http.HttpServ1etResponse;
/ / Importar paquetes java import java.io.IOException; import j ava. io. Printwriter; import j a v a .util. HashMap; import java.util.1terator;

public class ChatAdminServlet extends HttpServlet String chatRoomPath; String 1istRoomsPath; String chatAdminPath;

public void init ( ) throws ServletExceptiori { ServletContext context = getServletContext ( ) ; chatRoomPath = context .getInitParameter ("CHATROOM PATH") ; 1istRoomsPath = context.getInitParameter ( "LISTROOMS PATH" chatAdminPath = context. getInit Parameter ( "ADMIN PATH" ) ; if (chatRoomPath == null l I 1istRoomsPath == null I I chatAdminPath == null) { throw new Unavai lableExceptiori( "Applicatiori unavailable

public void doGet (HttpServletRequest req, HttpServletResponse r e s ) throws IOException, ServletException { res. setContentType ("textt/htmll') ; Printwriter out = res .getwriter ( ) ; out .println ("<html>") ; out .println iU<head><tit1e>Chat Room A d m i n i s t r a t i o r i < / t i t l e > < / h e a d > " ) ; out.println ("<body>") ; out.priritln ("<hl>Chat room administration?/hl>") ; out.println("<form method=\"POST\" action=\"" + res.encodeURL (chatAdmiriPath) + " \ ">" ) ;
/ / Comprobar salas d e chat existentes HashMap roornList = (HashMap) getServletContext ( ) .getAttribute ("roomList"); if (roomList ! = null) 1 It erator rooms = roomlist. keyset ( ) . iterator ( ) ;

if

( !rooms.hasNext ( ) ) { out .printlr,iW<p>There are no rooms</p>") ; else { out .println ("<p>Check the rooms you would like t o remove," + "and press Update List.</p>");

while

(rooms.hasNext(

) )

Sesiones de servlets, context0 v colaboraci6n


String roomName = (String) rooms. next ( ) ; ChatRoom room = (ChatRoom) roomList.get(roomName); out .println ("<input type=checkbox name=remove value=' " + room.getName() + " '>" + room.getName ( ) + "<br>") ;

1 1 1
/ / AAadir campos para aAadir una sala out .println ("<p>Enter a new room and the description<p>") ; out .println ("<table>") ; o u t .println ("<tr><td>Name:</td><td><irlput name=roomname " t "size=50></td></tr>") ; out .println ("<tr><td>DescriptiorI: </td>") ; o u t .println ( "<td><textarea name=roomdescr cols=40 rows=5>") ; out .println ("</textarea></td></tr>") ; out .println ("</table>");
/ / AT~adir bot6n enviar out. println ("<p><input type=submit value='Update List'>" ) ; out.println("<p><a href=\"" t 1istRoomsPath + "\">Chat Now</a>"); out.println("</form>"); out .println ("</body></html>"): out.close();

I
public void doPost(HttpServ1etRequest req, HttpServletResponse throws IOException, ServletException { HashMap roomList = null; res)

/ / Comprobar salas d e chat existentes synchronized (getservletcontext ( ) ) { roomList = (HashMap) getServletContext ( ) .getAttribute ("roomList"); if (roomList == null) { roomList = new HashMapi); getServletContext().setAttribute("roomList, roomlist);

t
1

/ / Actualizar la lista de la sala String[] removeList = req.getParameterValues ("remove"); synchronized ( roomList ) I if (removeList ! = null) { for (int i = 0; i < removeList.1ength; i++) roomList.remove(removeList[i]);

1 1

I
String roomName = req.getParameter("roomname"); String roomDescr = req. getparameter ("roomdescr") if
;

(roomName ! = null & & roomName.length() > 0 ) { synchronized (roomList) { roomList.put(roomName, new ChatRoom(roomName,

roomDescr) ) ;

I
doGet (req, res);

Capitulo 7
Las caracteristicas clave de esta clase son: El metodo i n i t ( ) carga las rutas a 10s tres sewlets desde el contexto. El metodo i n i t ( ) lanza una excepci6n U n a v a i l a b l e E x c e p t i o n si estos padmetros no han sido fijados en el descriptor de despliegue. El metodo d o p o s t ( ) comprueba el atributo de contexto llamado r o o m l i s t . Si no hay ninguno, crea un nuevo objeto HashMap y lo almacena en el contexto. Si el objeto HashMap no e s t l vacio, el metodo d o G e t () imprime entonces una lista de salas (el nombre de cada sala y una casilla de verificacidn) como parte del formulario para enviar una solicitud POST al mismo servlet. El mktodo d o p o s t ( ) procesa la solicitud POST; este mitodo puede eliminar simultineamente salas existentes y afiadir una sala nueva. Este metodo recupera el HashMap del contexto y dependiendo del tip0 de solicitud, elimina salas existentes (especificadas por el p a r h e t r o " r e m o v e " ) y/o aiiade una sala nueva. Despues de actualizar ~ a s h M a pel , mktodo d o p o s t ( ) invoca d o G e t ( ) ,para generar la h a de salas y la forma.

Observe que, puesto que HashMap estd almacenado en el contexto como un atributo, todos 10s servlets que participan en esta aplicacio'n pueden acceder a la lista de salas.
N o configuramos el atributo r o o m l i s t de s e r v l e t c o n t e x t despu6s de cadaactualizacidn del objeto HashMap. Este atributo contiene una referencia a1 objeto HashMap; actualizamos 10s datos d e ~ a s h M a ~ pero la referencia sigue siendo la misma y n o necesitamos reemplazar el objeto HashMap por otro HashMap. Configurar el atributo a la misma referencia de objeto seria redundante.

Sewlets para chat


Las clases L i s t R o o m s S e r v l e t y C h a t R o o m S e r v l e t implementan lainterfaz de usuario final. Ambas acceden a1 estado de contexto a travks del atributo r o o m L i s t configurado por C h a t A d m i n S e r v l e t . Antes de introducirnos de lleno en el c6dig0, examinemos el disefio en conjunto. La clase L i s t R o o m s S e r v l e t utiliza el objeto HashMap para obtener todos 10s objetos C h a t R o o m y envia una lista de ellos a1 cliente. El usuario puede seleccionar la sala a la que desea entrar, provocando que C h a t R o o m S e r v l e t seainvocada. La clase C h a t R o o m S e r v l e t utiliza primeroHashMap para obtener la sala de chat seleccionada por el usuario y despuks obtiene 10s objetos C h a t E n t r y de ChatRoom\Envia entonces una lista de todas las entradas del chat al cliente. Este sewlet es tambien invocado cuando el usuario envia un nuevo mensaje a la sal. En este caso, crea un nuevo objeto C h a t E n t r y y lo aiiade a la ChatRoom seleccionada.

U n usuario de chat de esta aplicaci6n, invoca primer0 la clase L i s t R o o m s S e r v l e t s , que enumera todas las salas disponibles y permite al usuario elegir un nombre y entrar en una sala. La captura de pantalla siguiente muestra la respuesta de L i s t ~ o o m~ s e r v l e despuks t de afiadir un par de salas:

Sesiones de servlets, context0 y colaboracion

Chat rooms
Create Roorns

Select the room you would k e to enter, or click on a name to see the description:
6F

B Chat r Java Sr&t

Chat

Enter your name

I~raid

C o m o acabamos de mostrar, la respuesta de este servlet muestra una lista de salas de chat. Cuando hace clic en una sala, este servlet muestra la descripci6n de un servlet. Alternativamente, puede seleccionar una sala de chat (utilizando el bot6n de opci6n situado a1 lado del nombre de la sal), introducir un nombre (nombre de perfil) y hacer clic en E n t e r para entmr en la sala de chat:
/ / Importar paquetes d e servlet import javax.servlet .ServletEx~:eptior~; import javax.servlet.Servlt3tContext; import j a v a x . s e r v l e t . h t t p . H t t p S e r v 1 e t ; import j a v a x . servlet. htkp. HttpSession; import j a v a x . s e r v l e t . h t t p . H t t p S e r v 1 e t R e q u e s t ; import j avax. servlet .http. HttpServletRespor~se; / / Importar paquetes java import java.io.IOExceptlon; import j ava. io. F r i n t W r i t e r ; import java. util. HashMap; import java. u t i l . I t e r a t o r ; import j ava. n e t .URLEncoder;

public class ListRoomsServlet extends HttpServIet String chatAdrninPath; string 1istRoomsPath; String chatRoomPath;

public void init() [ ServletContext context = getServletContext0; chatAdminPath = context .getInitFarameter ( " A D M I N N P A T H 1 ' )

Capitulo 7
1istRoomsPath = context.getInitParameter("LISTRO0MS PATH"); chatRoomPath = context.getInitParameter("CHATRO0M PATH"); if (chatRoomPath == null I I 1istRoomsPath == null I I chatAdminPath == null) { throw new UnavailableExceptior~ ( "Applicatior~ unavailable. " )

I
public void doGet(HttpServ1etRequest request, HttpServletResponse response) throws IOException { response. setContentType ("text/htm19') ; Printwriter out = response.getWriter ( ) ; String expand = request .getparameter ("expar~d") ; HttpSession session = request.getSession(); String profileName = ( S t r i n g ) sessior1.getAttribute("profi1eName"); if (profileName == null) profileName = " " ;

l
out .println ("<html>"); out.println("<head><title>Chat rooms</title></head>"); out .println ("<body>"); out .println ("<hl>Chat rooms</hl>") ; out.println("<form method=POST action=\"" + chatRoomPath out .println ("<p><a href=\"" + chatAdminPath + "\">Create Rooms</a></p>") ;

+ "\">"

);

/ / Obtener la lista d e salas HashMap roomList = ( H a s h M a p ) getServletContext().getAttribute("roomList"); if (roomList == null) { o u t .println ("<p>There are no rooms available right now. </p>") ; 1 else { / / AAadir cajas d e radio para seleccionar una sala out.println("Se1ect the room you wouldlike to enter," t "or click on a name to see the description:<p>");
Iterator rooms = roomList.keySet().iterator(); boolean isFirst = true; while (rooms.hasNext ( ) ) { String roomName = (String) rooms. next ( ) ; ChatRoom room = (ChatRoom) roomList.get(roomName); String 1istRoomsURL = 1istRoomsPath t "/?expand=" + URLEncoder.encodk(room~ame); 1istRoomsURL = response.encodeURL(listRoomsURL); out.println("<input type=radio name=roomName value=\"" t roomName t " \ " " t (isFirst ? " CHECKED" : " " ) t ">" + "<a href=\"" t 1istRoomsURL t " \ " > " t roomName t "</a><br>" ) ; isFirst = false;

/ / Mostrar descripci6n si se solicita if (expand ! = null 6 6 expand.equals(roomName)) { out.println("<blockquote>"); if (room.getDescription() .length( ) == 0) { out.println("No description available."); ] else { out.println(room.getDescription());
1

Sesiones de servlets, context0 v colaboracion

/ / Afiadir un carnpo para el nombre del perfil out .println ("<p>Enter your name: " ) ; out .println ("<input narne=profileNarne value=' " t profileName t " ' size=30>");

/ / Afiador bot6n enviar out.println("<p><input out.println("</form>");

type=subrnit value='Enterl>");

l
out .println ("</body></html>") ; out. close ( ) ;

I I
El mCtodo GET H T T P es utilizado para invocar el sewlet, por lo que utilizamos el mCtodo doGet ( ) para generar una pigina HTML con una formulario que contenga la lista de salas, el campo de nombre de usuario y el b o t h Enter (Intro). Para generar la lista de salas de chat, este mktodo invoca el metodo getAttribute ( ) en Servletcontext para obtener la lista de salas de chat. El sewlet tambiCn crea una sesi6n para cada usuario. Observe que, corno hernos analizado en el ejemplo anterior, todos 10s URL estin codificados para hacer uso de la reescritura de URL en el caso de que 10s cookies no Sean aceptados por usuarios del chat. La d a r e ChatRoomServlet C o m o hernos antes, la clase List RoomsS ervl et genera una pigina con una etiqueta <form> con el atributo de accion configurado en el nombre del ChatRoomServlet. El formulario contiene un control de bot6n de opci6n que alberga el nombre de la sala seleccionada con el nombre del usuario y utiliza el metodo POST para invocar de nuevo el sewlet. La clase ChatRoomsServlet se muestra a continuaci6n:
/ / Importar paquetes d e servlet import j avax. servlet. ServletException; import j avax. servlet . U n a v a i i l a b l e E x c e p t i u r ~ ; import javax.servlet.ServletContext; import javax.servlet.http.HttpServ1et; import javax.serv1et.http.HttpSession; import javax.servlet.http.HttpServ1etRequest; import javax.servlet.http.HttpServ1etResponse;

/ / Importar paquetes java import j ava. io. IOException; import java.io.PrintWriter; import java. util .HashMap; import java. util. Iterator;
public class ChatRoomServlet extends HttpServlet String chatRoomPath; String 1istRoomsPath;
{

public void i n i t ( ) throws ServletExceptio?~ { ServletContext context = getServl etcontext ( ) ; chatRoomPath = context. getInitParameter ("CHATROOM PATH" ) ; 1istRoomsPath = context .getInitParameter ("LISTROOMS PATH") ; if(chatRoomPath == null I I 1istRoomsPath == null ) {

Capitulo 7
throw new UnavailableExceptior~ ("Application unavailable." ) ;

I
public void doGet(HttpServ1etRequest req, HttpServletResponse throws IOException, ServletException { res. setContentType ("text/htrnll') ; Printwriter out .= res.getWrlter ( ) res)

ChatRoom room = getRoorn(req, res); if (room == null ) { throw new ServletException ("Room not found" )

1
/ / Comprobar si es una solicitud para iista d e rnensaje o un formulario String listpar = req.getParameter("listV; if (listpar ! = null & & listPar.equals("true") ) { writeMessages(out, room, getProfileNarne(req) ) ; 1 else { out .println("<html>"); out .println ("<body>"); out .println ("<form method=\"post\" action=\"" + res.encodeURL(chatRoornPath) + " \ " target=\" top\">");
out .prir,tln ("<p>Enter your message: </p>"); out .println ("<input name=\"msg\" size=\"30\">" )
;

/ / ARadir un bothn Enviar out .println ("<p><input type=submit value='Send

M e s s a g e 1 > " );

/ / ARadir un bothn Salir out .println ("</form>") ; out.println("<form action=\"" + res.encodeURL(listRoomsPath) + " \ " method=\"get\" target=\" top\">") ; out.println("<input type=submit value=Exit>"); out.println ("</form>"i ;
out .println ("</body></htrnl>");
1

out. close (

) ;

I
public void doPost(HttpServ1etRequest req, HttpServletResponse throws IOException, ServletException { res. setContentType ("text/html"); ChatRoom room = getRoomireq, res); if (room == null) { throw new ServletException ("Room not found" ) res)

1
String profileNarne
=

getProfileNameireq);

/ / Guardar rnensaje si hay alguno String msg = req.getParameter("msg"); if (msg ! = null & & msg.length() ! = 0) { room.addChatEntry ( n e w ChatEritry (profileName, msg) )

I
writeFrame (res, room) ;

Sesiones de servlets, context0 y colaboracion


private String getProfileName(HttpServ1etRequest req) 1 HttpSession session = req.getSession (true); String profileName = (String) session.getAttribute("profi1eName"); if (profileName == null) 1
/ / ;Ha entrado er, una sala por primera vez? profileName = req. getparameter [ "profileNamee' ) ; if (profileName == null I I profileName.length() profileName = "A spineless spy";
)

==

0) 1

session.setAttribute ("profileNarne", profileName) ; else 1


/ / ;Ha entrado en una sala nueva con un nombre nuevo? String newName = req.getParameter ("profi1eName1') ; if (newName ! = null & & newName.length() > 0 &&!newName.equals(profileName)) { profileName = newName; session.setAttribute ("profileName", profileName) ;

return profileName;
1

private ChatRoom getRoom(HttpServ1etRequest req, HttpServletResponse res) throws IOException 1 HttpSession session = req.getSession(true); PrintWriter out = res.getWriter ( ) ; String roomName = (String) session.getAttribute ("roomNarne"); if (roomNarne == null) 1
/ / ;Acaba d e entrar? roomName = req.getParameter ("roomh'ame") ; if ( roomName == null I I roomName.length() == 0) 1 writeError(out, "Room not specified"); return null;

1
session.setAttribute["roomName", roomName);

1 else 1
/ / ;Ha entrado en una sala nueva? String newRoom = req. getparameter [ "roomName") ; if (newRoom ! = null & & newRoom.length() > 0 &&!newRoom.equals(roomName)); roomNarne = newRoom; s e s s i o n . setAttribute ("roomNarnee', r o o m N a m e ) ;

HashMap roomList = ( H a s h M a p ) getservletcontext ( ) .getAttribute ("roomList"); ChatRoom room = (ChatRoom) roomlist .get (roomName); if (room == null) { writeError(out, "Room " + roomName + " not found"); / return null;

1
return room;
1

private void writeError ( PrintWriter out, String msg)

Capitulo 7
out .println ("<html>") ; out.println("<head><title>Error</title></head>"); out .println("<body>") ; out .println ("<hl>Error</hl>"); out.println(msg); out .println ("</body></html>" ) ;
1

private void writeFrame(HttpServ1etResponse res, ChatRoom room) throws IOException { Printwriter out = res.getWriter( ) ; out.println("<html>") ; o u t .println ("<head><title>" t room.getName ( ) t "</title></head>" ) ; out.println("<frameset rows='50%,50%' border=O frameborder=no>"); out.println("<frame src=\"" t res.encodeURL(chatRoomPath) t "?list=true\" name=\"list\" scrolling=\"auto\">") ; out.println("<frame src=\"" t res.encodeURL(chatRoomPath) t "?list=false\" name=\"form\" scrolling=\"auto\">"); o u t .println ("<noframes>"); out.println("<body>") ; out.println("Viewinq this page requires a browser capable o f " t "displaying frames.") ; out.println ("</body>"); out .println ("</noframes>") ; out .println ("</frameset>") ; out.println("</html>"); out.close ( ) ;

t
private void writeMessages(PrintWriter out, ChatRoom room, String profileName) { StringBuffer s b = r~ew S t r i n g B u f f e r O ; out .println ("<html>") ; out.println("<head><meta http-equiv=\"refresh\" content=\"5\"></head>"); out .println ("<body>") ; out .println ("<b>Room: " t room.getName ( ) t "</b><br>I1 t "<b>Identity: " t profileName t "</b><br>");

/ / Enurnera todos 10s mensajes d e la sala if (room.size() == 0 ) { out.println("<font color=red>There are no messages 1 r 1 this room "yet</font>") ; 1 else { Iterator entries = room.iterator(); while (entries.hasNext()) { ChatEntry entry = (ChatEntry) entries. next ( ) ;

"

String entryName = entry.getProfileName ( ) ; if (entryName.equals(profi1eName)) { out .print ("<font color=blue>") ; 1 out .println (entryName t " : " t entry.getMessage ( if (entryName.equals (profi1eName)) ( out.print ("</font>");

"<br>");

1 1

1
o u t .println ("</body></html>") ;

I
I

Sesiones de servlets, context0 y colaboracion


En comparaci6n con el resto de las clases de esta aplicaci6n, este servlet parece algo mas complicado. Las siguientes capturas de pantalla muestran una sesi6n de chat en desarrollo: Los siguientes puntos clave deben ayudarle a navegar por esta clase:

Room: EJB Chat Identity: Craig

E n . . , : . , m? goc,d h o k r on E l B ~itvdopmcnt? Adnw rve heard 'ProfcsnondEJB' and Troiessional Java


c.rq

serve^

Room: EJB Chat Identiry: Adrian Crag Know any good books on ETB development? ~ . h . mP ! c hcard "Prt.fcssrona1E J E ' and 'Frofrs~cnd Java S c m z P r , r p r m ' thrn ' 3 ~ s Yrtrr a c gmd place; I* .-mt C r q ?hanks

Enter your mess@

II

I
Send Me5zoge

Cada una de las anteriores capturas de pantalla tiene dos marcos HTML, el marco superior es utilizado para presentar 10s mensajes enviados en la sala, mientras que el marco inferior es utilizado por el usuario para introducir nuevos mensajes. Los marcos son generados en el metodo w r i t e F r a m e ( ) , invocado e n d o P o s t 0 . El metodo d o G e t ( ) desempeiia el papel dual de generar ambos marcos. Para decidir si debe generar una lista de mensajes, o un formulario para introducir un mensaje nuevo, utiliza el parimetro de solicitud l i s t . Si este parametro es t r u e (cuando la solicitud GET es generada por el marco superior), d o G e t ( ) genera la h a de mensajes invocando el metodo w r i t e M e s s a g e s ( ) . Si este parimetro no estf presente en la solicitud (cuando la solicitud GET es generada por el marco inferior), simplemente genera la forma estitica. El metodo d o p o s t ( ) es invocado cuando el usuario introduce un mensaje nuevo. d o p o s t ( ) recupera la sala de chat actual utilizando el metodo getRoom ( ) y el nombre de usuario de la sesi6n. Utilizando estos datos, crea una nueva C h a t E n t r y y la atiade a la sala de chat. Invoca entonces w r i t e F r a m e ( ) ,que fuerza 10s solicitudes GET, una para cada marco. Puesto que mensajes nuevos pueden ser enviados a la sala casi continuamente, debemos actualizar periddicamente el niarco superior. Utilizamos la metaetiqueta actualizar para recargar s) para la automiticamente este marco cada 5 segundos. Vease el m e t o d o w r i t e ~ e s s a g e ( implementation de esta funci6n.

Capitulo 7

Configuracion del chat


Para configurar, construir y desplegar la sala de chat, considere 10s siguientes pasos:

Una pagina de biemenida


Cree una pigina i n d e x . html:

<p>Click <a href="/chat/servlet/chatAdrnin">here</a> administer chat rooms.</p> <p>Click <a href="/chat/servlet/listRooms">here</a> current chat rooms, and to join a chat room.</p>

to to view

El prop6sito de esta pigina es sencillamente proporcionar vinculos a 10s servlets de la aplicaci6n.

Descriptor de despliegue
~ s t es e el descriptor de despliegue:

< ! DOCTY P E Web-app


PIJBLIC "-//Sun Microsystems, Inc. //DTD Web Application "http://java.sun.com/j2ee/dtds/Web-app 2 3.dtdn>
2. 3 / / E N 1 '

Sesiones de servlets, contexto y colaboracion

Ademis de declarar las tres clases de servlets, este descriptor de despliegue tambiin define tres parimetros de contexto adicionales. C o m o hemos analizado previamente, cada uno de estos parametros define una cadena que apunta a un servlet. {Par quk son necesarios? En esta aplicacion, 10s servlets generan contenido que apunta a otros servlets por ejemplo, el contenido generado por la clase Lis tRoomsServlet tiene vinculos a ChatRoomsS ervlet y ChatAdminServlet. En lugar de codificar estos valores en cada uno de 10s servlets, hemos utilizado estos parimetros para obtener 10s verdaderos URL de 10s servlets.

Cuando despliegue esta aplicacion (raiz de contexto como chat), ver6 en la pantalla context 10s parimetros de contexto que hemos definido:

Y para 10s servlets ChatAdmin y ChatRoom,puede tambikn ver el modelo de U R L que ha sido representado como un ~ l i a s :

)I

$ chal

1)

Contexi Parameters Merenced in Code

- -

tbG5W

8 chalAdmin

Introduzca en su navegador http:Nlocalhost:8000/chat para acceder a1 archivo de bienvenida creado anteriormente. Utilice el vinculo de administraci6n para crear salas de chat.

Sesiones de servlets. context0 v colaboracion


Para ver la lista de salas de chat y unirse a una de ellas, puede utilizar el b o t h C h a t NOW en la pigina de Utilice 10s adrninistracibn, o introducir directarnente el URL http://localhost:800O/chat/se1~let/listRoorns. botones de opcidn para seleccionar una sala de chat, introduzca su nornbre y haga clic en E n t e r (Intro) para entrar en la sala de chat.

En el rnodelo tipico de servlet, un servlet recibe una solicitud HTTP, ejecuta alguna 16gica de aplicaci6n y prepara la respuesta. Esto cornpleta un recorrido solicitud-respuesta para el cliente. Sin embargo, hay diversas situaciones en las que este rnodelo bisico no es adecuado:
0 U n servlet recibe una solicitud HTTP de un cliente, procesa la 16gica de aplicaci6n y una Pigina JavaServer dirige la respuesta. En este caso, el servlet no es responsable de la generaci6n de la respuesta. En su lugar, la pigina JSP es responsable del contenidodinimico. 0 U n servlet recibe una solicitud HTI'P de un cliente, procesa parcialmente la bgica de aplicaci6n y pasa la solicitud a otro servlet. El segundo servlet completa la 16gica de aplicaci6n y bien prepara la respuesta, o solicita una pigina JSP para dirigir la respuesta.

En arnbas situaciones, el servlet no es cornpletamente responsable de procesar de una solicitud. En su lugar, delega el procesamiento en otro servlet (o en un pigina JSP, que es equivalente a un servlet en el period0 de ejecuci6n). Hay dos tipos de soluci6n para enfrentarse a 10s requisites anteriores:
0 Encadenado de servlet Este fue un enfoque muy utilizado en su momento y fue apoyado por algunos de 10s vendedores de rniquinas de servlet. Aunque no se ajusta a la especificaci6n API Java Servlet, para cornpletar la explicaci6n, encontrari una breve descripci6n a continuaci6n. 0 Lanzamiento de solicitud El lanzamiento de solicitud permite a un servlet lanzar la solicitud a otro recurso (un servlet, una pigina JSP, o cualquier otro recurso). Con anterioridad a la versi6n 2.2 del API Servlet, este enfoque solia denominarse "comunicaci6n inter-servlet". El API solia proporcionar un metodo para obtener una instancia de otro servlet utilizando un nombre. VCase la docurnentaci6n del ahoradesaprobado m C t o d o g e t s e r v l e t ( ) de la interfaz j a v a x .s e r v l e t s e r v l e t c o n t e x t . A partir de la versi6n 2.2 del API, 10s lanzamientos de solicitudes sustituyen a esta funcionalidad.

Encadenado de servlet
El encadenado de servlet es anterior a J2EE y su modelo de componentes. La idea del encadenado de servlet es rnuy sencilla: disefie un grupo de servlets, cada uno de 10s cuales realiza una tarea diferente. Despues de desarrollar estos servlets, configure su miquina de servlet para especificar una cadena de servlets para un determinado alias de ruta URL. Una vez que la miquina de servlet recibe una solicitud para este alias, invoca 10s servlets en el orden especificado. Es similar a1 encauzamiento en Unix, donde la salida de un programa se convierte en entrada para otro prograrna en el tubo. Suponga que tiene 10s servlets A, B y C ejecutando tres partes de un proceso de solicitud-respuesta para un linico servicio de clientes. Asumamos que /custService es el alias dado a esta cadena (/custService=A, B, C). Considere un navegador que envia una solicitud a la ruta URL que apunta a este alias. La miquina de servlet envia todas las solicitudes para este alias a1 servlet A. Despues de ejecutar el metodo de servicio del

Capitulo 7
sewlet A, la miquina de sewlet invoca el mktodo de servicio del servlet B, seguido por el mktodo de servicio del servlet C. La respuesta final es enviada entonces al cliente. Resumiendo Cste es el encadenado de servlet. Consulte la siguiente figura para un anilisis de este enfoque:

i1
'
1

1
1Cliente (navegador) 1

Mhquina de sewlet Ahas

l-

4sewlet A Servlet B

I
I
I
'
I

---

-.

1 4 -

I Servlet C

La caracteristica clave del encadenado de servlet es la posibilidad de configurar la miquina de servlet para realizar el encadenado. Durante la configuracih, especifique el orden en el que estos servlets deberian ser invocados.
El encadenado de sewlets fue inicialmente introducido en el Sewidor Web Java per0 nunca form6 parte de la especificaci6n del API Sewlet. Todavia encontrari algunos libros que hagan referencia al encadenado de sewlets per0 recuerde que kste no es un rasgo estindar y que no se ajusta a la mayoria de contenedores Web de la actualidad. En su lugar, debe considerar utilizar el enfoque de Ianzamiento de solicitudes.

--

El lanzamiento de solicitudes perrnite a un servlet o a una pigina JSP lanzar una solicitud a otro servlet, (o a otra pigina JSP, o incluso a una pigina HTML normal), que serl entonces responsable de cualquier procesamiento posterior y de generar la respuesta. Cuando el contenedor Web recibe una solicitud, construye objetos de solicitud,y respuesta e invoca uno de 10s metodos de servicio del servlet con 10s objetos de solicitud y respuesta. Este es un proceso en el que el contenedor Web lanza una solicitud al servlet. iQuC ocurre si este servlet quiere lanzar la misma solicitud a otro servlet despuCs de alg6n procesamiento preliminar? Para este prop6sit0, el primer servlet debe ser capaz de obtener una referencia al segundo sewlet. Utilizando esta referencia, el primer servlet puede lanzar una solicitud al segundo servlet. En tkrminos sencillos, esto es el lanzamiento de solicitudes. El API Java Servlet tiene una interfaz especial llamada j avax servlet .RequestDispatcher para este proposito.

La interfaz RequestDispatcher
public Interface RequestDispatcher

Esta interfaz encapsula una referencia a otro recurso Web en una ruta especificada dentro del alcance el puedeserutilizadopara r mismo context0 de servlet. U n objeto j avax. servlet .~ e q u e s t ~ i s p a t c h e lanzar solicitudes a otros servlets y piginas JSP. Esta interfaz tiene dos mktodos, que le permiten delegar el procesamiento de solicitudes-respuestas en otro recurso, despuks de que el servlet llamante haya finalizado cualquier procesamiento preliminar.

Sesiones de servlets, contexto y colaboracion


El d t o d o forward0
public void forward(Serv1etRequest request, ServletResponse response) throws ServletException, java.io.IOException

Este metodo le permite reenviar la solicitud a otro senlet o pigina JSP, o a un archivo HTML en el servidor; este recurso acepta la responsabilidad de producir la respuesta.

El d t o d o include0
public void include(Serv1etRequest request, ServletResponse response) throws ServletException, java.io.IOException

Este metodo le permite incluir el contenido producido por otro recurso en la respuesta del servlet Ilamante.

Obtener un objeto RequestDispatcher


Existen tres formas de obtener un objeto RequespDispatcher para un recurso:

Aunque estos metodos tienen el mismo prop6sit0, el uso depende de la informaci6n que tenemos a nuestra disposici6n. El metodo getRequestDispatcher ( ) acepta una ruta de URL que haga referencia a1 recurso objetivo. Sin embargo, el m e t o d o g e t ~ e q u e s t ~ i s p a t c h en e rjavax .servlet .~ e r v l e t ~ o n t e x requierela t ruta absoluta (es decir, el nombre de ruta debe empezar p o d ) . Por ejemplo, si tiene un servlet / myWebApp/servlet /servlet 1 y quiereobtenerel objeto RequestDispatcherpara/my~eb~pp/ servlet /servlet2,debe especificar la ruta completa relativa a1 contexto raiz. Aqui el contexto raiz es / m y ~ e b ~y p lp arutaabsolutaes/servlet/servlet2. El mismo metodo en j 3 w x . servlet .ServletRequest acepta tanto rutas absolutas como relativas. En el ejemplo anterior, ahora puede tambien utilizar servlet 2 como ruta.
Un j a v a x . ~ e r v l e t . ServletRequest estaasociadoaunaruta URLyelcontenedor Web puede utilizarlo para resolver rutas relativas en rutas absolutas.

El metodo getNameDispat che r ( ) es un metodo de conveniencia que acepta un nombre asociado a1 servlet. Este es el mismo nombre que especifica en el descriptor de despliegue en el elemento <servlet name>. Observe que 10s recursos objetivos (except0 10s recursos estiticos) deben im~lementar el mismo tip0 de solicitud H T T P que el que recibe el servlet original.

Revision de Apoyo Tknico


Revisemos ahora y mejoremos la aplicaci6n de Apoyo Tecnico del liltimo capitulo. Consideraremos las siguientes caracteristicas adicionales:
0 En lugar de recabar datos del c o m ~ r a d o r (como nombre, a~ellidos y nlimero de tekfono) cada

vez, introduzcamos una pigina de registro del comprador.

Capitulo 7
0

Utilizando la direccidn de e-mail del comprador, determine si un comprador es "conocido" o es un comprador nuevo. Si el comprador es nuevo, redirija al comprador a la pigina de registro.

0 Despuks del registro, dirija a1 comprador a un senlet de respuesta. 0

Si el comprador es un comprador "conocido", dirijale directamente a1 senlet de respuesta.


\

0 Mantenga tablas de bases de datos independientes para el apoyo de solicitudes y datos de

comprador. Como veri muy pronto, estas mejoras requieren un uso extensivo de lanzamientos de solicitudes. La siguiente figura muestra el recorrido completo de esta aplicacidn:
I SI esta reglstrado
POST
- -

Reenwar --

techsuppxt.Mml

Reenwal

Servletdeapoyotecn~co
I

SI noesta registrado
I

El recorrido que acabamos de mostrar es muy sencillo. La solicitud procedente de techsupport. html se dirige a Techsupport Servlet. Si el comprador ha sido registrado previamente, Techsupport Servlet reenvia la solicitud a ResponseServlet. De no ser asi, el recorrido sigue hasta la pigina register html, para recabar informacidn sobre el posible comprador. A1 enviar el formulario de esta pigina, la solicitud pasa a RegisterServlet, que inserta 10s datos del comprador en la base de datos. Despuks del registro, el recorrido sigue hasta ResponseServlet.

Responses ervlet genera una pigina con un mensaje de respuesta, e incluye la salida de Banners ervlet. BannerServlet simplemente escribe una "insignia" HTML sin cabeceras ni pies de <body>, etc.). pigina H T M L (<html>,

Consideremos ahora la implementaci6n.

La pagina techsupp.html
~ s t es a igual que la pigina que cred en la aplicacidn original de Apoyo Tkcnico, except0 en que el nombre, el apellido y el nGmero de telkfono del cliente ya no estin incluidos en el formulario. El formulario envia la so~icituda~ech~u~~ort~ervlet:

Sesiones de servlets, context0 v colaboracion


< t a b l e a l i g n = " c e n t e r " width="100%" c e l l s p a c i n g = " 2 " c e l l p a d d i n g = " 2 " > < tr > < t d aligr~="right">Email< : /td> < t d > < i n p u t t y p e = " T e x t m name="email" a l i g n = " l e f t " size="25"></td> </ t r > <tr> < t d align="right">Software:</TD> <td> < s e l e c t name="software" SIZE="l"> < o p t i o n value="Word">Microsoft Word</option> <option value="Excel">Microsoft Excel</option> < o p t i o n value="Access">Microsoft A c c e s s < / o p t i o n > < o p t i o n value="Outlook">Microsoft O u t l o o k < / o p t i o n > </select> </ t d > < t d a l i g n = " r i g h t " > O p e r a t i r ~ gSystem: < / t d > <td> < s e l e c t name="os" s i z e = " l " > < o p t i o n value="95">Wir~dows 9 5 < / o p t i o n > < o p t i o n value="98">Wir~dows 9 S < / o p t i o n > < o p t i o n value="NT">Wir~dows N T < / o p t i o n > < o p t i o n value="2KPro">Windows 2000 P r o < / o p t i o n > < o p t i o n v a l u e = " 2 K S e r v e r " > W i r ~ d o w s 2000 S e r v e r < / o p t i o r ~ > < o p t i o n value="XP">Windows X P < / o p t i o n > </select> </td> </ t r > </table> <br>Problem Description <br> < t e x t a r e a name="problem"

cols="50"

rows="4"></textarea>

Esto tiene como resultado el siguiente formulario:

Capitulo 7

Technical Support Request


Emat
(xander@sunnydale corn

Opera-

System: windows 98

Problem Dtscri~ticm
P r o b l e m opening v o r ~ o o 4

A
I ]

-.

Submit Request

~ s t es a una version revisada de la clase T e c h s u p p o r t s e r v l e t original, que inserta por primera vez la solicitud del comprador en la base de datos y despuis comprueba la base de datos para ver si existe un comprador con la direccion de e-mail proporcionada. Si hay una, utiliza un lanzamiento de solicitud para redirigir a1 comprador a R e s p o n s e S e r v l e t . Sin embargo, si el comprador no esti registrado, envia la s o l i c i t u d a r e g i s t e r .h t m l :
/ / Impnrtar paquerrc de eervlet import j a v a x . s a r v l e t . RequestDispatcher; impnrt j a v a x . s e r v l e t .Servlr:tE:iception; implt>rt j a v a x . s e r v l e t . I l r ~ a v a i l r r h l e E x c r p t i o n ; i m p o r t javax.cervlet.http.HttpServ1et; import j 3 v a x . s e r v l e t . http.HttpSeseir:r:n; import javax.servlet.http.HttpServletReq~~est; import j3vax.eervlet. h t t p . Htt~~ServletResp~:~r~se; / / Irnpt:. r t a r p a q l r e t e s j a v a import iava.io.PrintWriter; ir n p > r t j a v a . IOExctption; i m p o r t j a v a . s r ~ 1C N - , r ~ r ~ e c t i o r ~ ; i m p o r t ja v a . s s q l . F r e p a r e d S t a t e m e r ~ t ; irnp~lrt java.sq1 .ResultSet; i m p n r t j a v a .s'-[l. S O L E z ~ : e p t i ~ ? r ~ ; i m p a r t javax.sql. D a t a S c ~ l r c e ; I i n p : > r t j a v a s . narnirt(-j. I n i t i a l f 7 ~ > r r t n : i t ; i my r t_ j a v a s . n a m i n g .N,qmir~qE>:t:eption;
i d > .

,:I

Sesiones de servlets. context0 v colaboracion


HttpServletResponse response) throws S e r v l e t E x c e p t i o n , IOException { HttpSession session = request.getSession( ) ;

//

E x t r a e r i n f o r m a c i 6 n d e l comprador d e l a s o l i c i t u d S t r i n g e m a i l = request.getParameter("emai1"]; S t r i n g software = request .getparameter ("software"); String os = request .getparameter ("os"); S t r i n g problem = r e q u e s t .getparameter ("problem" ) ;

i n t r e q u e s t I d = 0; Connection connection = n u l l ; String insertStatementStr = "INSERT INTO SUPP REPIJESTS (EMAIL,


"(?,

SOFTWARE,

OS,

PROBLEM) VALUES

"

?,

?,

?)";

S t r i n g selectCustomerStr = "SELECT CUSTOMERS. FNAME, t "CUSTOMERS.EMAIL = ? " ;

CUSTOMERS. LNAME

FROM CUSTOMERS WHERE

"

//
try

Insertar
{

solicitud

de

apoyo d e l

comprador

en

la

base de datos

I n i t i a l C o n t e x t i n i t i a l = new I n i t i a l C o n t e x t ( ) ; D a t a s o u r c e d s = ( D a t a s o u r c e )i n i t i a l . l o o k u p ( " j d b c / T e c h S u p p o r t " ) ; c o n n e c t i o n = da .getConnection ( ) ; PreparedStaternent i n s e r t S t a t e m e n t = connection. preparestatemer~t ( i n s e r t S t a t e m e r ~ t S t r; ] i n s e r t s t a t e m e n t . s e t s t r i n g (1, e m a i l ) ; i n s e r t s t a t e m e n t . s e t s t r i n g ( 2 , s o f t w a r e ); insertStatement. setstring (3, o s ); i n s e r t s t a t e m e n t . s e t s t r i n g ( 4 , problem) ;

// Verifique

a h o r a s i e l c o m p r a d o r e s t & o no r e g i s t r a d o . Preparedstatement selectStatement = connection.prepareStatemer~t( s e 1 e c t C u s t o m e r S t r ) ; s e l e c t S t a t e m e n t . s e t S t r i n g [ 1, e m a i l 1 ;

if

//

( r s . r t e x t ( )1 { S i l o e n c u e n t r a , a d j u n t e nombre y a p e l l i d o a S t r i n g f l r s t N a m e = r s . g e t s t r i n g ("FNAME") ; S t r i n g lastName = rs.qetString("LNAME"); request.setAttribute("firstNamee', f i r s t N a m e ) ; r e q u e s t . s e t A t t r i b u t e ( " l a s t N a m e e ' , 1 a s t N a m e );

la

solicitud

/ / Invoque ahora e l s e r v l e t d e r e s p u e s t a . RequestDispatcher rd = getservletcontext ( ) .getNarnedDispatcher ("response"); rd. forward (request, response) ;
]

else

/ / .El c o m p r a d o r no e s t d r e g i s t r a d o .
session.setAttribute ("email",

Es n e c e s a r i o r e g i s t r a r l o email);

ahora.

RequestDispatcher rd = request.getRequestDispatcher("/register.html"); rd.forward(request, response);

1 catch

(NaminqException n e )

Capitulo 7
throw

1 catch

new S e r v l e t E x c e p t i o n ( " JNDI e r r o r " , n e ) ; (SQLException s q l e i { t h r o w new S e r v l e t E x c e p t i o n ( " D a t a b a s e e r r o r " , s q l e ) ;

I
finally { i f (cor,nection != n u l l ) i try I connection. c l o s e ( ) ; ) c a t c h ( SQLException s q l e )

II

I
I

I
1

Fijese en 10s cambios que hemos realizado a esta sewlet a partir de su versi6n original del capitulo anterior. Este sewlet inserta la solicitud de apoyo del comprador en la base de datos como siempre. Sin embargo, la instrucci6n INSERT n o inchye nombre, apellido y nGmero de telkfono. Como veri en breve, el esquema de la base de datos incluye ahora una tabla del comprador con estos datos. En segundo lugar, este sewlet utiliza ahora lanzamientos de solicitudes para implementar el recorrido deseado. Para decidir si se debe solicitar el registro del comprado, este sewlet comprueba la informaci6n del comprador en la tabla de Comprador. Si no hay entrada, este sewlet reenvia a1 usuario a la pigina de registro. Si n o es asi, este sewlet envia a1 usuario a la pigina de respuesta. Este proceso ilustra c6mo puede implementar el recorrido entre sewlet de una forma dinimica.

La pagina register.html
Esta pigina contiene un formulario que recaba informaci6n de registro del usuario: el nombre, el apellido y el nGmero de telkfono del comprador. El formulario envia la solicitud a R e g i s t e r c u s t ome r s e r v l e t :
<html> <head> <tltle>Customer Registration</title> </head> <body> <center><hl>Customer Registration</hl></cer~ter> <hr> Please r e g i s t e r . < f o r m action="/techSupport/servlet/register" method="POST"> <table> <tr> < t d > F i r s t Name: < / t d > <td><input type="TextM </tr> < tr > < t d > L a s t Name:</td> < t d > < i r ~ p u tt y p e = " T e x t l ' </tr> <tr> < t d > P h o n e Number: < / t d > <td><input type="TextW </tr> </table>

Sesiones de servlets, contexto v colaboraci6n


Esto produciri el siguiente forrnulario:

Customer Registration
Please register First Name: Last Name,
l~lexander l~arrls

Phone Number: 1555-1 21 2


Submit Request

9Liio

rr

~ocal Mranet

r:

Este servlet registra inforrnaci6n del usuario. Despuks del registro, este s e n l e t envia la solicitud a ResponseServlet:
//
I m p ortar payuetes d e servlet import javax.servlet.RequestDispatcher; import javax.aervlet.Serv1etException; import javax.servlet.~navailableException; i m p o r t javax.servlet.http.HttpServ1et; i m p o r t javax.serv1et.http.HttpSession; import javax.servlet.http.HttpServ1etRequest; import javax.servlet.http.HttpServletResponse;

//

Importar paqlletec j a v a import java.in. Printwriter; import java.io.IOException; impnrt java . s q l .Connection; import java.sq1. Preparedstatement; import java.sql.S@LExcsption; import j avax.sql.DataSuurce; import javax.naming.Ini tialContcxt; import j avax. naminq .NaminqException; public class ReqisterCllstnmerServlet extends HttpServlet
{

Capitulo 7

public void doPost(HttpServ1etRequest request, HttpServletResponse response) throws ServletException, IOException [ HttpSession session = request.getSession(); 1; String fname = request .getparameter ("txtFnamee' Strir~g lname = request.getParameter ("txtLnamee') ; String ernail = (String) sessior~.getAttribute("emai1"); String phone = request.getParameter ("txtPhone"); Connection connection = null; String insertStatementStr = "INSERT INTO CUSTOMERS VALUES I?, ?, ?, ? ) "; try I InitialContext initial = new InitialContext ( ) ; Datasource d s = ( DataSource)initial. lookup ("jdbc/TechSuppnrt"); connection = d s .~getConr~ection ( ) ; PreparedStatement insertstatement = c o n n e c t i o n . p r e p a r e S t a t e m e r ~ t(insertStatemer1tStr); insertStatement .setstring (1, email) ; ir~sertStatement .setstring (2, fname); insertstatement .setstring (3, lname); insertStatement.setstring ( 4 , phone) ;

]
]

catch (NamingException n e ) 1 throw n e w ServletException("JND1 error", n e ) ; catch (SQLException s q l e ) { throw new ServletExceptior~("Database error", s q l e ) ; finally 1 if (connection ! = null) { try { connection.close0; ] catch (SQLException sqle) [ I

I
request .setAttribute ("firstNamee', fname); request .setAttribute["lastNamee', lname) ; / / Invoque ahora el servlet Respuesta. RequestDispatcher rd = getservletcontext ( ) .getNamedDispatcher (l'responsell) ; rd. forward(request , response) ;

Este servlet muestra un mensaje que confirma que la solicitud del comprador (y el perfil, si ha sido introducido), ha sido registrada. Este sewlet "incluye" BannerServlet para incluir una insignia en el contenido:
/ / Importar paquetes d e servlet import javax.serv1et.RequestDispatcher; import javax.servlet.ServletException;

Sesiones de servlets. context0 v colaboracion


import javax.servlet.http.HttpServ1et; import javax.servlet.http.HttpServ1etRequest; import javax.servlet.http.HttpServ1etRespor~se;

/ / Importar paquetes java import j ava. io. Printwriter; import j ava. io. IOException;
public class ResponseServlet extends HttpServlet
[

protected void doPost(HttpServ1etRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response);

protected void doGet(HttpServ1etRequest request, HttpServletResponse response) throws ServletExcept ion, IOException { response. setContentType ("text/htmll') ; PrintWriter out = response.getWriter ( ) ; / / Enviar acuse a1 comprador out .println ("<html>") ; out.println("<head><title>Customer Service Response</title></head>"); out .println ("<body>"); out.println("<hl>Customer Service Request Received</hl>"); out .println ("<p>Thank you for your request. " ) ; out.println("<p>Your request has been recorded and will be " + "responded to within three business days.");

/ / Incluir una insignia RequestDispatcher rd = request.getRequestDispatcher("/servlet/banner"); rd. include (request, response) ;


out .println ("</body></html>"); out. close ( ) ;

I I

Este servlet genera un banner muy sencillo con el nombre del usuario actual, seguido por un pie de pigina estindar. Observe que este servlet no establece el tip0 de respuesta porque esti incluido en la respuesta que es g e n e r a d a p o r e l ~ e s p o n s e ~ e r v l e t :
/ / Importar paquetes d e servlet import j avax. servlet. ServletException; import javax.servlet.http.HttpServlet; import j a v a x . s e r v 1 e t . h t t p . H t t p S e s s i o i - I ; import javax.servlet.http.HttpServ1etRequest; import javax.servlet.http.HttpServ1etRespor~se;

/ / Importar paquetes java import java. io. Printwriter; import j ava. io. IOException;
public class BannerServlet extends HttpServlet
[

protected void doPost(HttpServ1etRequest request,

Capitulo 7
HttpServletResponse response) throws ServletException, IOException { doGet(request, response);

1
protected doFet(HttpServ1etRequest request, HttpServletResponse response) throws ServletException, IOException { H t t p S e s s i n n s e s s i o n = request.getSession( ) ;
void

S t r i n g f i r s t b l a m e = ( S t r i n g ) r e q u e s t . q e t A t t r i b u t e ("firstNamee') ; S t r i n g l a s t N a m e = ( S t r i n g ) request . g e t A t t r i b u t t ( " 1 a s t N a m e " ) ; PrirltWriter o u t


=

response.getWriter

();

out.println("<hr>"); nut.println("Currerrt User: " t firatName t " " t l a s t N a r n e ) ; out.prlntln("<hr>"); nut .println [ " X Y Z C o r p o r a t i o n , C u s t o m e r Service. " ) ; out.println [ " < R R us a t 1.800.xyz.corp.sbr>");

I
ResponseServlet y ~ a n n e r ~ e r v t l juntosproducenestasalida: e

kchiw
Atlas

- -@@
I )
..

Edicih

Ver

Favorites

Herrmientas

Ayuda

I e ~ k y e d a BFavwRos

@Multimdia

3I

&$

Customer Service Request Received


Thank you for your request
Your request has been recorded and wdl be responded to w i t . three business days. Current User: Alexander Harris XYZ Corporahon, Customer Senrice.

Sesiones de servlets, context0 v colaboracion


Configuracion de Apoyo Tbcnico y despliegue
El descriptor de despliegue es similar a la versi6n del capitulo anterior per0 con nuevos sewlets afiadidos:

< ! DOCTY PE Web-app

PUBLIC "-//Sun Microsystems, Ir~c. //DTD Web Applicatlor~ 2. 3//ENW "http: / / java. sun. corn/ j Zee/dtds/Web-app_2-3 .dtdv'>

Obviamente, tambiCn necesitamos modificar la base de datos. Elimine la tabla existente y vuelva a crearla utilizando el siguiente SQL:
CREATE TABLE SUPP REQUESTS(REQUEST I D EMAI L SOFTWARE 0S PROBLEM CREATE TABLE CUSTOMERS (EMAIL FNAME INT DEFAULT AUTOINCREMENT INITIAL 1 INCREMENT 1 NOT NULL, VARCHAR ( 4 0 ) , VARCHAR(401, VARCHAR ( 40 ) , VARCHAR(256) ) ; VARCHAR ( 4 0) PRIMARf KEY, VARCHAR(15),

Capitulo 7
LNAME PHONE

Si todavia tiene la aplicacion de Apoyo Tecnico del capitulo anterior desplegada, pliCguela y sustitGyala por esta. Recuerde asegurarse de que el recurso de la base de datos esta referenciado en el despliegue. Para probar la aplicacion, introduzca el URL http:/1localhost:8000/techSupport. Debe poder navegar por el recorrido representado a1 principio de esta section. N o olvide que necesita que la base de datos se estk ejecutando.

Utilizar RequestDispatcher para colaboracion


En esta aplicacion, hemos utilizado R e q u e s t D i s p a t c h e r para 10s siguientes objetivos:

Reenviar una solicitud a ResponseServlet


El servlet T e c h s u p p o r t S e r v l e t comprueba la base de datos del usuario para saber si Cste ya esti registrado. Si lo esti, la solicitud es reenviada a R e s p o n s e S e r v l e t :
if ( rs. next ( ) ) { String firstName = rs.getString ( " F N A M E " ); String lastName = rs.getString ( " L N A M E " ) ; ; r e q u e s t . setAttribute ("firstI'Jame", firstI-Iame) r e q u e s t . setAttribute ("1astNamee', 1 a s t N a m e ) ; / / Invcque ahnra el servlet d e Respuesta. RequestDispatcher rd = getServletContext().getNamedDispatcher("response"); rd. forward ( r e q u e s t , r e s p o n s e ) ;

Puesto que R e p o n s e S e r v l e t tiene un alias llamado response (especificado en el descriptor de despliegue), podernos utilizar el metodo g e t N a m e d D i s p a t c h e r ( ) para obtener un objeto R e q u e s t D i s p a t c h e r para el servlet de respuesta. La rnisrna tecnica es utilizada por R e g i s t e r C u s t o m e r S e r v l e t parareenviar~aso~icituda~esponse~equest. Observe que estamos utilizando el metodo s e t A t t r i b u t e ( ) en el objeto solicitud para afiadir 10s atributos de nornbre y apellido puesto que la solicitud es enviada d e s d e ~ e c h ~ u p p o r t ~ e r voldesde et R e g i s t e r S e r v l e t a R e s p o n s e S e r v l e t , queentonces i n ~ l u ~ e ~ a n n e r ~ e r B va ln en te . rServlet puede obtener estos atributos del objeto Request rnientras genera el contenido de insignia. Remitase a la fuente de B a n n e r s e r v l e t para ver corn0 es la insignia.

Reenviar solicitud a reglter.html


Si el usuario no e s t i registrado, es dirigido a r e g i s t e r . h t m l :
RequestDispatcher rd = request .getRequestDispatche~("/register. html" ) rd. forward ( request, response) ;
;

Utilizarnos larutaabsohta de la pigina r e g i s t e r . h t m l para obtener u n R e q u e s t D i s p a t c h e r del objeto H t t p S e r v l e t R e q u e s t , e invocamos el mitodo f o r w a r d ( ) para reenviar la solicitud. Observe que, puesto que register.htrn1 solo puede ser invocado utilizando una solicitud GET, el forrnulario de t e c t i s u p p .h t m l debia utilizar el metodo GET.

Puesto que el metodo forward ( ) reenvia la solicitud a otros recursos, el servlet llamante ( ~ e c h S u p p o r t S e r v l e tno ) debe realizar ninguna informaci6n salida a la respuesta. Por ejemplo, no debe i n v o c a r g e t ~ r i t e r ( ) para obtener un objeto j a v a . i o .P r i n t w r i ter y escribir contenido en 61. Sin embargo, si alglin contenido es escrito en la respuesta, debe invocar el mitodo reset ( ) en el objeto respuesta.

Sesiones de servlets, contexto y colaboracion


Por ejemplo, no debe invocar getwriter ( ) para obtener un objeto j ava . io. Printwriter y escribir contenido en el. Sin embargo, si a l g h contenido es escrito en la respuesta, debe invocar el metodo reset ( ) en el objeto respuesta.

lncluir insignia en ResponseSewlet


ResponseServlet incluye en su respuesta una insignia generada por BannerServlet. El prop6sito de esta insignia es imprimir el nombre del usuario actual y un mensaje estitico de insignia. El metodo doGe t ( ) ResponseServlet incluyeelsiguientecbdigo:
R e q u e s t D i s p a t c h e r r d = request.qetRequestDispatcher("/servlet/hanrier"); rd. i n c l u d e ( r e q u e s t , r e s p o n s e ) ;

Observe la diferencia entre forward ( ) y include ( ) . Mientras que forward ( ) convierte a1 nuevo servlet en responsable absoluto de generar la respuesta, include ( ) incluye meramente la respuesta del servlet invocado en la respuesta del servlet Ilamado. Utilizando este enfoque, puede componer respuestas procedentes de multiples servlets.

En este capitulo, hemos cubierto algunos de 10s aspectos importantes de programaci6n de desarrollo de aplicaciones basadas en servlets:
0

Registro de sesiones y estado de asociacion (atributos) a sesiones: En todos 10s ejemplos de este capitulo, hemos utilizado el objeto sesi6n para mantener el estado de una sesibn. Contextos de servlet: En la aplicaci6n de chat, hemos visto c6mo el contexto de servlet le permite mantener el estado de la aplicacion. Tambien hemos utilizado el contexto de servlet para acceder a 10s lanzadores de solicitudes. Colaboraci6n de servlet: La aplicaci6n de Apoyo Tecnico revisada ilustra como 10s lanzadores de solicitudes pueden ser utilizados para crear flujos condicionales entre servlets y piginas estiticas.

Ya hemos abarcado la mayor parte del API Servlet. En el siguiente capitulo, analizaremos otra caracteristica conocida como filtrado de servlet.

Filtros para aplicaciones Web


Los filtros son la incorporaci6n rnis reciente a la tecnologia de servlet Java. La versi6n 2.3 de la especificaci6n Servlet introduce filtros corno un rnedio flexible de interactuar con solicitudes y respuestas HTTP antes y despu.6~ de que el contenedor Web invoque recursos Web incluido servlets. En el irnbito de las tecnologias J2EE, 10s filtros ocupan un lugar aparte. Los componentes de aplicacion J2EE estin controlados por el contenedor. Recuerde que cuando un cliente presenta una solicitud a un cornponente J2EE, corno un servlet, pigina JPS o EJB, el contenedor recibe ]as solicitudes e invoca despuks las instancias de cornponente apropiadas gestionadas en el period0 de ejecuci6n del contenedor. En el caso del contenedor Web, recibe solicitudes HTTP e invoca varios recursos de aplicaci6n Web incluido servlets, piginas JSP, archivos HTML, imigenes, etc. Es decir, el contenedor Web es el interceptor para solicitudes HTTP a recursos. El proceso de interceptaci6n irnplica varios pasos incluido identificar la aplicaci6n Web, encontrar asociaciones de ruta a recursos, cornprobar la autentificaci6n y a u t o r i z a c h ~e , invocar recursos. C o n las diversas funciones de 10s servlets, no hay ninguna instalaci6n para participar en este proceso de interceptaci6n. N o puede carnbiar, controlar o visar en el modo en que el contenedor invoca 10s recursos. Por ejernplo, considere la necesidad bisica de controlar solicitudes para un tip0 especifico de archivo estitico (corno ciertos tipos de irnigenes o docurnentos) en el contenedor y registrar las solicitudes en una determinada base de datos. Para construir esta funcionalidad, lo que necesita es una instalaci6n para conectar alguna 16gica durante el proceso de rnanejo de solicitudes H'ITP. Es decir, necesita una funci6n para participar en el proceso de interceptaci6n. El prop6sito de un filtro es proporcionar esta funci6n. iPor qu.6 son especiales 10s filtros? En J2EE 1.3,los filtros ofrecen el tinico rnecanisrno por el que podernos introducir c6digo para participar en el proceso de interceptaci6n del contenedor. Aunque 10s filtros estin lirnitados a1 contenedor Web (es decir, podernos filtrar solicitudes H T T P per0 no podernos filtrar solicitudes a EJB, etc.), podernos realizar diversas tareas titiles con la ayuda de filtros en el contenedor Web. C o n filtros podemos configurar el contenedor Web para invocar ciertos objetos filtro durante el proceso de solicitud-respuesta HTTP. De este rnodo, corno desarrolladores de aplicaciones Web, podemos adaptar

Capitulo 8
el mod0 en que las solicitudes H T T P son manipuladas en un contenedor Web. Antes de analizar las posibilidades, examinemos primer0 detalladamente quk es exactamente un filtro. Este capitulo presenta una introduccion al filtro API. Para obtener algunos conocimientos pricticos, perfeccionaremos una de las aplicaciones Web construidas en capitulos anteriores para ilustrar la capacidad de 10s filtros en 10s contenedores Web.

i Q u e es un filtro?
U n filtro es un objeto parecido a un sewlet y controlado por un contenedor que puede ser insertado de forma declarativa en el proceso de solicitud-respuesta HTTP.
A1 igual que un servlet, un objeto filtro es instanciado y controlado por el contenedor y sigue un ciclo de vida similar a1 de un servlet. C o m o veremos mis adelante en este mismo capitulo, un filtro tiene cuatro etapas: instanciacion, inicializaci6n, filtrado y destruction. Estas etapas son similares a las etapas de instanciaci6n, inicializaci6n, revision y destrucci6n de un servlet. Los filtros tambikn siguen un proceso de despliegue cercano a1 de 10s servlets. De hecho, el API de un filtro es muy similar a1 de la interfaz de servlet (un filtro tambikn opera en solicitudes H T T P para producir y manipular de forma adicional las solicitudes y respuestas). Entonces, ten quk se diferencia un filtro de un servlet? Para ver la diferencia, consideremos la participation de 10s filtros en el proceso de solicitudrespuesta http:

Cadena defikros

3 F~ltro

, Recursosmagenes, Web (estat~cos. etc


HTML,

Dln5rn1cos: SewletlJSP)

En esta figura, hay una cadena de tres filtros que participan en el proceso de solicitud-respuesta. Cada filtro (de izquierda a derecha en la figura) puede manipular la solicitud y la respuesta o implementar alguna 16gica (incluido actualizar la sesion H T T P o el context0 de servlet) y solicitar a1 contenedor que invoque el siguiente filtro (si hay a l p n o ) en la cadena de filtro. Finalmente, despuks de invocar el ultimo filtro, el contenedor procesa el verdadero recurso Web. El proceso de manejo de recursos es el mismo que el que hemos estudiado en 10s capitulos anteriores. Alternativamente, cualquier filtro de esta cadena puede elegir abortar el proceso, e informar de un error en la respuesta HTTP. Las flechas entre 10s filtros y entre el tercer filtro y el recurso Web son 10s objetos j avax. s e r v l e t . S e r v l e t R e q u e s t y
javax.servlet.ServletResponse.

En este proceso, despuks de cada filtro sea procesado, el control es transferido a1 siguiente filtro de la cadena. De un mod0 similar, despuks de que el recurso Web haya sido procesado, el contenedor devuelve el hilo de ejecuci6n a1 ultimo filtro. Este paso continua hasta que el control es devuelto a1 primer filtro. De este modo, cada filtro tiene una oportunidad de participar tanto antes como despuks de invocar el recurso Web. Analicemos ahora algunas de las posibilidades que ofrecen 10s filtros:

Filtros para aplicaciones Web


0 Validar solicitudes H T T P

Cada filtro tiene acceso a1 objeto solicitud HTTP y puede, por lo tanto, validar 10s contenidos de las solicitudes HTTP. Si una solicitud no es vilida (es decir, contiene parirnetros no vilidos, si faltan parirnetros requeridos o si 10s valores de 10s parirnetros provistos no son vilidos), el filtro puede abortar el procesarniento e inforrnar de errores HTTP a1 contenedor. De este rnodo, podernos evitar implementar cualquier bgica de validacion en servlets o piginas JSP. Tambikn podernos extender esta idea para preprocesar 10s parirnetros de solicitud HTTP.
0

Solicitudes H T T P de registro Basindonos en 10s contenidos de solicitudes HTTP, podemos implernentar el registro de acceso de adaptacion para todos 10s recursos Web. Habitualrnente, el registro es la prerrogativa del servidor Web y norrnalrnente no hay control sobre corn0 se realiza el registro. Los filtros nos ofrecen un asa para implernentar nuestro propio registro (adernis de la del servidor). Con filtros, podemos solicitar registro especifico de aplicacion. Por ejernplo, podernos construir un registro basado en eventos de ernpresa especificos; 10s filtros nos perrniten exarninar solicitudes para determinar 10s eventos. Autorizar solicitudes H T T P La autorizacidn es el proceso para cornprobar si el cliente puede acceder a un deterrninado recurso. Norrnalmente, las aplicaciones Web implementan codigo de autorizacion de adaptacion en cada servlet y pigina JSP. En su lugar, podernos implementar autorizacidn de adaptacion en un filtro e incluir el filtro para todas las solicitudes HTTP. Tambikn podernos confiar en la autorizacion declarativa controlada por contenedor Web. Gesti6n de contenido Una aplicacion rnis sofisticada podria necesitar gestionar el contenido dinirnicarnente. Por ejernplo, podernos desencadenar procesos para crear contenido dinirnicarnente en el que la verdadera solicitud H T T P puede representar. Puesto que el contenedor invoca el filtro antes de intentar localizar el verdadero recurso HTTP, podemos dejar que el filtro Cree el recurso si es necesario. Por ejemplo, si la solicitud H T T P entrante corresponde a una irnagen para un sisterna topogrifico de representation, podernos invocar la bgica respectiva para crear la imagen, de rnodo que el contenedor Web la encontrara a1 final de la cadena de filtros.

O Proporcionar u n entorno H T T P de adaptaci6n para servlets y piginas JSP Tarnbikn podernos utilizar el mecapisrno de filtro para rnodificar 10s objetos de solicitud y respuesta (y, de este rnodo, tarnbikn la sesion). Por ejernplo, podernos afiadir datos adicionales a1 objeto solicitud o completar parirnetros ausentes/por defecto. Tarnbikn podernos reernplazar 10s objetos de solicitud y respuesta para proporcionar rendirniento adicional.
Debernos destacar que todas estas tareas podrian realizarse en un servlet, aunque con alguna dificultad. Existen, sin embargo, algunas diferencias:

O U n servlet es equivalente a un recurso Web except0 en que es dinirnico. U n filtro,.por otro lado, no es un recurso a1 que sirve el contenedor. En carnbio, el contenedor invoca un fdtro rnientras procesa una solicitud para "servir" a un recurso. D e este rnodo, 10s filtros nos ofrecen la oportunidad de participar en el proceso de servir cualquier recurso Web. Observe que en la figura anterior, el recurso Web podria ser cualquier recurso estindar (un recurso estitico corno un archivo HTML, una irnagen, un archivo clase para un applet, etc., o un recurso dinimico corno un servlet o una pigina JSP. O C o n la ayuda de filtros, podernos separar de un rnodo efectivo la 16gica de 10s servlets. Podernos introducir declarativarnente filtros sin cambiar nuestros servlets O Los filtros pueden ser utilizados en cualquier aplicacion Web, incluido 1as de contenido cornpletarnente estitico.

Capitulo 8
La lista anterior de situaciones es muy habitual aunque podriamos implementar una 16gica mris compleja en 10s filtros. Es tentador comparar 10s filtros con el mecanismo lanzador de solicitudes que hemos analizado en el capitulo anterior. Sin embargo, 10s filtros son diferentes del lanzador de solicitudes en varios aspectos:

O El API lanzador de solicitudes va dirigido a servlets y piginas JSP para reenviar el procesamiento a otro recurso Web o incluir 10s contenidos de otro recurso Web. Sin embargo, reenviar e incluir son dos funciones que s610 pueden tener lugar desde servlets o JSP que son clasificados como recursos Web. N o podemos utilizar este API para controlar lo que sucede antes de que la solicitud llegue a un servlet o JSP. Por otro lado, un filtro es invocado antes de que la solicitud alcance un servlet, o JSP, o, de hecho, cualquier otro recurso.
0 N o podemos utilizar el API lanzador de solicitudes para intervenir en la invocaci6n de recursos no

servlet o JSP, como un archivo estitico. Sin embargo, un filtro, si puede ser utilizado con este fin. En las siguientes secciones, estudiaremos el API filtro con mis detalle con la ayuda de algunos ejemplos.

Para ilustrar mejor el API filtro, implementemos primero una clase de filtro de prueba para contar el nGmero de solicitudes a piginas HTML desplegadas en una aplicaci6n Web. El prop6sito de esta prueba es ilustrar el proceso de creaci6n y despliegue de filtros. Este ejemplo consiste en lo siguiente:

O U n filtro para contar el numero de solicitudes para archivos HTML. Este filtro almacena la cuenta en el contexto de servlet actual. O Algunos archivos HTML. Para reforzar la ilustraci6n, insertaremos un simple archivo HTML en la raiz de esta aplicaci6n Web.

U n servlet para mostrar el contador almacenado en el contexto.

Nuestro centro de atenci6n en este ejemplo es la clase filtro; el resto del c6digo es necesario Gnicamente para mostrar el filtro en funcionamiento y analizaremos en el API en detalle en la siguiente secci6n. Creemos primero la clase filtro llamada CounterFilter. Como hemos destacado en capitulos anteriores, el c6digo fuente para 10s ejemplos de este libro esti disponible para su descarga en http:// www.wrox.corn:
import import import import import import import import
j avax. servlet. Filter; j avax .servlet.FilterConfig; j avax. servlet. Filterchain; javax.servlet.Serv1etContext; javax.servlet.ServletRequest; j avax. servlet. ServletResponse; javax.servlet.ServletException; javax.servlet.http.HttpServ1etRequest;

import java.io.IOException; public class CounterFilter FilterConfig config; public void implements Filter
{

init ( FilterConfig config) {

Filtros Dara a~licaciones Web


this .config
=

config;

I
public void doFilter(Serv1etRequest request, ServletResponse response, Filterchain chain) throws IOException, ServletException { ServletContext context
=

config.getServletContext();

Integer count = (Integer) context .getAttribute ("cour~tt'); if (count == null) { count = new Integer(0);

I
count = new Integer (count.intvalue ( ) t 1 ) ; context. setAttribute ("count", count) ;

/ / Invocar el siguiente filtro (si hay alguno) chain .doFilter (request, response);

1
public void d e s t r o y 0
{ }

I
Esta clase crea un filtro implementando la interfaz j a v a x .s e r v l e t .F i l t e r , una interfaz que es muy similar a la de un sewlet. Tiene 10s habituales mktodos i n i t ( ) y d e s t r o y ( ) . La 6nica diferencia estriba en que el filtro tiene un metodo d o F i l t e r ( ) que es invocado durante el proceso de interceptacidn. Estudiaremos en breve estos mktodos m6s detenidamente. Por el momento, s610 necesitamos considerar el cddigo en el cuerpo de este metodo. Este c6digo utiliza el objeto F i l t e r C o n f i g para acceder a1 contexto de sewlet. A1 ser invocado por primera vez, este filtro configura un atributo " c o u n t " . Durante posteriores invocaciones, el filtro actualiza la cuenta en el contexto. Solicita entonces que el contenedor procese filtros posteriores invocando el metodo d o F i l t e r ( ) en el objeto de cadena. Puesto que d o tenemos un filtro en este ejemplo, la d t i m a llamada tiene como resultado el envio de contenidos del archivo i n d e x . h t m l en la respuesta. Pero, icdmo invoca el contenedor al filtro en primer lugar? Volvamos a esta pregunta despues de crear el resto de la aplicacidn. El siguiente paso es crear el sewlet para mostrar el contador:
import import import import import

javax.servlet.Serv1etContext; javax.servlet.ServletException; javax.servlet.http.HttpServ1et; javax.servlet.http.HttpServ1etRequest; javax.servlet.http.HttpServ1etRespor~se;

import j ava. io. IOException; import java. io. Printwriter; public class Displaycount extends HttpServet ( protected void doGet(HttpServ1etRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext context Integer count
= =

getServletContext0;

(Integer) context .getAttribute ("count");

response. setContentType ("text/htmll') ; Printwriter out = response.getWriter( ) ;

Caoitulo 8
out .prir~tln ( " < h t m l > " ); o u t . p r i n t l n ("<meta http-equiv=\"Pragrna\" o u t . p r i n t l n ( " < b o d y > " ); i f ( c o u n t != n u l l ) { out .println("The current count is " + I else 1 o u t . p r i n t l n ("Count r ~ o ta v a i l a b l e . " ) ;

content=\"no-cache\">"i

count .intValue ( ) ) ;

1
o u t . p r i n t l n ("</BODY>") ; o u t . p r i n t l n ("</html>") ; out. close ( ) ;

I
Este servlet lee la cuenta actual desde el context0 y la imprime en la respuesta. Aunque podriamos crear cualquier archivo HTML, en este ejemplo utilizaremos el siguiente HTML:

<body> < h l > C o u r ~ t e rF i l t e r < / h l > < p > C l i c k < a href="/counter/servlet/display">here</a> of t h e f i l t e r . < / p > </body> </htrnl>

to

see

the

effect

Para desplegar el archivo anterior, Cree el siguiente descriptor de despliegue, tambiin dentro del directorio \WEB- INF\:

< ! DOCTY PE W e b - a p p
PUBLIC
"-//Sun

Mlcrosysterns,

I n c . //DTD

Web A p p l i c a t i o n

2 . 3//ENM

"http://java.sun.corn/j2ee/dtds/Web-app 2 3 . d t d W >

Filtros Dara a~licaciones Web


En este descriptor de despliegue, 10s dos elementos, < f ilter> y < f ilter-mapping>, aparecen destacados. El primer0 de estos elementos declara un filtro en esta aplicaci6n Web; el orden en el que aparecen 10s elementos de filtro en el descriptor de despliegue representa el orden de la cadena de filtro. En este ejemplo, el filtro es denominado c o u n t e r y e s implementado utilizando la clase C o u n t e r F i l t e r que hemos definido antes. Observe que estos dos elementos son similares a 10s elementos <servlet> y
(servlet-mapping>.

El segundo elernento, <filter-mapping,, es el que indica a1 contenedor qu6 tip0 de solicitudes deben ser filtradas con un determinado filtro. En el descriptor de despliegue anterior, el elemento <filtermapping> declara que el filtro c o u n t e r debe ser aplicado a todos 10s recursos con extension .html. Siempre que el contenedor recibe una solicitud para un archivo HTML de esta aplicaci6n, el contenedor invoca este filtro antes de servir el archivo HTML.

Despliegue
Para desplegar esta aplicacion, debernos prirnero crear un archivo Web (WAR) que contenga todos 10s archivos requeridos para la aplicaci6n. Asegurese de que tiene 10s siguientes archivos en las siguientes ubicaciones:
co~r~t_er/ i d e x . lhtrnl WEB-IN/ Web. xrnl classes/ CounterFllter. class DisplayCount. c l a s s

Cree ahora el archivo WAR utilizando el comando j ar:


jar

-':vi

c3urlt?1 .war

index.htrn1

WEB-IN

Ahora estamos preparados para desplegar el archivo WAR. Inicie el servidor de Implementaci6n de Referencia JZEE ejecutando el archivo j 2ee. bat en el directorio % J2EE-HOME% \bin. Una vez haya finalizado, ejecute el archivo deploytool. bat en el mismo directorio, para iniciar la herramienta de despliegue. Cuando se cargue la herramienta de despliegue, Cree una nueva aplicaci6n llamada counte r.
Web WAR (Agregar aplicacion

Aiiadirnos entonces el archivo counter .war a la aplicaci6n utilizando la opcion Add to Application I Web WAR) del menu File (Archivo).

Ahora ya estamos preparados para desplegar la aplicacidn en el servidor. Seleccione Deploy (Desplegar) (Herramientas). En la primera pantalla s d o es necesario que comprobemos que estamos del menu ~ o o l s desplegando la aplicaci6n correcta. En la siguiente pantalla, necesitamos proporcionar el context0 que utilizaremos para navegar nuestra aplicaci6n. Configurelo en counter. Proceda hasta la pantalla final y seleccione F i n i s h (Finalizar) para desplegar la aplicaci6n en el servidor. Para probar el filtro en funcionamiento, arranque nuestro navegador Web e introduzca http:// localhost:8000/counter/index.html.Esta pigina muestra un vinculo a1 servlet Displaycount y serL asi:

Capitulo 8

Archive

Edcibn

Ver

Favorit05

Hwranient*

Ayuda

Counter Filter
Click herF to see the effect of the Elter.

&L

~ O

rl
@GXKanet

Antes de hacer clic en este vinculo, vuelva a cargar la pigina index.html unas cuantas veces. Cuando hacernos clic en el vinculo que nos lleva a1 servlet Displaycount,observarernos que el contador esti siendo incrernentado. Cuando actualizarnos la pigina index.html,el filtro estd siendo invocado por el contenedor. El filtro esti incrementando la cuenta y almacendndola en el contexto de servlet. Para que siempre obtengamos la dtima cuenta, evitamos la cacht del navegador incluyendo una metaetiqueta HTTP "no-cache". Podemos afiadir algunos archivos HTML mis a esta aplicaci6n Web para cornprobar que el contador seri incrementado siempre que el archivo HTML sea solicitado. Adernds de ilustrar corno funcionan 10s filtros, este ejernplo tarnbiCn ilustra un punto clave: el rnecanisrno de filtro le perrnite interceptar solicitudes y respuestas HTTP independienternente de 10s verdaderos recursos. En la siguiente section examinaremos 10s detalles del API filtro.

El API filtro
El API filtro consiste en las siguientes interfaces y clases:
U javax.servlet.Filter

La interfaz que todos 10s filtros deben irnplernentar.

O javax.servlet.Fi1terConfig
Una interfaz que proporciona accesos a 10s parimetros de iniciahaci6n de filtro y al contexto de servlet. Esta interfaz es creada por el contenedor y pasada a la instancia de filtro durante la iniciak~~i6n.
0 javax.servlet.Fi1terChain Una abstracci6n de una cadena de filtro. Esta interfaz le perrnite invocar el siguiente filtro de In cadena, o si el filtro llamante es el liltimo filtro de la cadena, a1 recurso final de la cadena.

Estudiemos ahora estas interfaces y clases individualrnente con mds detenirniento.

La interfaz de filtro
public interace Filter

Filtros Dara a~licaciones Web


Esta interfaz del paquete j a v a x . s e r v l e t encapsula 10s metodos de ciclo de vida de un filtro. Los metodos de ciclo de vida incluyen i n i t ( ) y d e s t r o y ( ) ,que son invocados durante la inicializaci6n y destrucci6n del filtro, y el mCtodo d o F i 1t e r ( ) ,que es invocado siempre que hay un par solicitud/ respuesta que debe ser filtrado.

public void init(Fi1terConfig

config) throws ServletException

El contenedor invoca este metodo antes de poner el filtro en servicio. Durante la inicializaci6n, el contenedor envia la informaci6n de configuracibn (parimetros de inicializacibn) a1 filtro a traves de un o b j e t o ~ i l t e r ~ oi n gf .

public void doFilter(Serv1etRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException

El contenedor invoca este metodo mientras procesa un filtro. Utilizando el objeto F i l t e r C h a i n , cada filtro puede instruir a1 contenedor para que procese el resto de la cadena de filtro. Veremos este proceso con mas detenimiento en breve. Observe que este metodo es similar a1 metodo s e r v i c e ( ) de un servlet con la diferencia del tercer parimetro.

public void destroy

()

El contenedor invoca este metodo antes de sacar a un filtro de servicio. Esto puede suceder en el cierre del contenedor o cuando la aplicacibn es plegada. Todos estos metodos son metodos invocados por el contenedor utilizados durante un ciclo de vida del filtro. El ciclo de vida de un filtro consiste en las siguientes etapas. Compirelas con el ciclo de vida de un servlet. Instanciar El contenedor instancia cada clase de filtro en el arranque del contenedor o a@n tiempo antes de que una instancia de filtro sea requerida para invocacibn. Para cada aplicacidn Web, el contenedor mantiene una instancia por filtro.'Esta etapa es similar a 10s servlets que no implementan la interfaz S i n g l e T h r e a d S e r v l e t . En el caso de contenedores Web distribuidos, el contenedor mantiene una instancia por aplicacibn por miquina virtual. Inicializar Despues de instanciar un filtro, el contenedor invoca el metodo i n i t contenedor pasa parimetros de inicializacibn a la instancia de filtro.
()

. Durante esta Ilamada, el

Invocar Para aquellas solicitudes que requieren un filtro para procesar, el contenedor invoca el metodo d o F i 1t e r ( ) que es requerido para implementar la 16gica de filtro. Destruir El contenedor invoca este metodo antes de retirar el filtro de servicio. En este metodo, el filtro puede implementar cualquier 16gica de limpieza. Estas etapas quedan representadas en la siguiente figura. De estas etapas, durante el ciclo de vida de un filtro, solo la fase de filtrado sucede varias veces, mientras que 10s eventos restantes ocurren normalmente s61o una vez. En la prictica, 10s primeros dos pasos tiene lugar en el arranque del contenedor o cuando se despliega la aplicaci6n, mientras que el ultimo paso tiene lugar en el cierre del contenedor o cuando de

Capitulo 8
pliega la aplicacion (utilizando herramientas proporcionadas por el contenedor, si hay alguna). El contenedor siempre asegura que un filtro es inicializado antes de que tenga lugar el filtrado.

Los mktodos init ( ) y doFilter ( ) pueden ambos lanzar una excepcion ServletException, mientras que el mktododo~ilter ( ) tambiknpuede lanzar j ava . io. IOException.Cuandoestos mktodos lanzan una excepcion ServletExcept ion,el contenedor no puede continuar con la cadena de filtro, lo que significa que no puede senir el recurso Web a1 que representa la solicitud. Por lo tanto, en casos en 10s que desee que el contenedor s i n a el recurso sin tener en cuenta cualquier excepcion, es importante asegurarse de que 10s filtros consumen excepciones y registran estos casos adecuadamente.

La interfaz FilterConfig
public interface FilterConfig

Esta interfaz es la equivalente a servletconf ig para filtros. La interfaz proporciona acceso a1 entorno de filtros y cuenta con 10s siguientes mktodos: El d t o d o getFilterName0
public void getFilterName
()

Este mktodo devuelve el nombre del filtro tal y como esti especificado en el descriptor de despliegue. Por ejemplo, en el ejemplo anterior, el nombre del filtro es counter. El d o d o getlnitParameter0
public String getInitParameter(String name)

El mktodo devuelve el valor de 10s parimetros de inicializacion nominados o null si el parimetro no existe. Podemos especificar 10s parimetros de inicializacion en el descriptor de despliegue a1 declarar el filtro. El dodogetlnitParameterNames0
public Enumeration getInitParameterNames()

Este mktodo devuelve 10s nombres de 10s parimetros de inicializaci6n del servlet como una Enumeracion de objetos string o una Enurneracionvacia si el senlet no tiene parametros de inicializaci6n. El d t o d o getServletContext0
public ServletContext getServletContext()

Este mktodo devuelve una referencia a1 context0 de sewlet asociado a la aplicacion Web relevante.

La interfaz FilterChain
public interface FilterChain

Filtros Dara a~licaciones Web


Esta interfaz proporciona a1 filtro un asa para invocar el resto de la cadena de filtro. Cada filtro obtiene acceso a un objeto FilterChain cuando el mitodo doFilter ( ) es invocado. Utilizando este objeto, el filtro puede permitir a1 contenedor invocar el siguiente filtro de la cadena. La interfaz FilterChain tiene un finico mitodo:

El d t o d o doFilter0
public void doFilter(Serv1etRequest request, ServletResponse response)

Cuando un filtro invoca este metodo, el contenedor invoca el siguiente filtro de la cadena de filtro. Si el filtro que invoca es el filtimo filtro de la cadena, el contenedor invoca el recurso Web de la solicitud. La siguiente figura ilustra este proceso:

Cuando un filtro invoca el m6todo doFi 1te r ( ) sobre el objeto Fi lterChain,el contenedor invoca el siguiente filtro de la cadena. iY si el filtro no quiere seguir procesando? En este caso, el filtro puede sencillamente no invocar el mitodo doFi lter ( ) en el objeto Fi lterChain.Pero, (par qu6 no querria un filtro continuar con la cadena? Considere, por ejemplo, un filtro que valida la solicitud entrante. Si el filtro descubre que la solicitud esti incompleta, noes vilida, o es inapropiada, puede que elija abortar la cadena. En este caso, el mismo filtro puede escribir contenido adecuado en la respuesta.

Descriptor de despliegue para filtros


Como hemos visto en nuestro primer ejemplo, para desplegar filtros en una aplicaci6n Web, se requieren las siguientes entradas adicionales en el descriptor de despliegue:
0

U n elemento <filter> para declarar cada filtro. ~ s t es e similar a la declaration de servlet en el descriptor de despliegue y consiste en un nombre, <f ilter-name>,el nombre de clase cualificado del filtro, <f ilter-class> y cero o mis parimetros de inicializacion. Para cada parimetro, debemos especificar un nombre, <param-name> y un valor, <param-value>. Podemos opcionalmente especificar una d e s c r i p c i 6 n , < d e s c r i p t i o n > , para cada parimetro de inicializacion. U n elemento <f ilter-mapping> para especificar patrones URL. El contenedor utiliza asociaciones de patrones URL para determinar si uno o mis filtros deben ser invocados antes de procesar un recurso Web. El patron corresponde a1 URL asociado a1 recurso Web.

tC6mo utiliza el contenedor estas entradas para invocar una cadena de filtro? Consideremos un fragment0 de un descriptor de c6digo:

Capitulo 8

Esta declaraci6n asocia tres filtros para solicitudes empezando por /product/catalog/.Basindose en esta configuraci611, el contenedor forrna una cadena de filtro consistente en estos tres filtros. Si 10s URL fueran diferentes a estos descriptores, la cadena de filtros de llarnadas seria modificada, lo que significa que si hubiera una errata en el descriptor y la segunda definici6n de filtro no apuntara a1 rnismo URL, la cadena de filtro n o seria de 1 y despues 3. Siempre que el contenedor recibe una solicitud que ernpieza por / product/cat alog/, crea un objeto Filterchain que abstrae estos filtros e invoca el metodo doFil t er ( ) del primer filtro. El orden de las invocaciones de filtro esti deterrninado exclusivarnente por la organizaci6n del archivo del descriptor. DespuCs del procesamiento requerido, el primer filtro puede invocar el metodo doFi lter ( ) en la cadena de filtro. Esto provoca que el contenedor invoque el segundo filtro. El segundo filtro asi obtiene una oportunidad de seguir procesando la solicitud. DespuCs, puede invocar el metodo doFi lt er ( ) en el objeto de la cadena de filtro, que tiene corno resultado la invocaci6n del tercer filtro. Cuando el tercer filtro invoca el metodo doFi 1 ter ( ) ,el contenedor ernpieza a procesar el original. DespuCs de la conclusi6n del procesarniento, el control regresa a1 tercer filtro. Este proceso continda hasta que el control regresa a1 primer filtro, despues del cual finaliza el proceso de filtrado. Hay tres puntos clave a destacar aqui:

O El contenedor confia en el orden en el que las asociaciones son declaradas en el descriptor para
componer una cadena de filtro.

O Cada filtro tiene una oportunidad de procesar antes y despuks de que el verdadero recurso sea
procesado. Esto se debe a1 anidamiento de las llamadas doFi 1ter ( ) . Este proceso es cornpletarnente declarativo. Puede activar o desactivar filtros inchyendo o eliminando declaraciones de representaci6n de filtro en el descriptor de despliegue. ~ s t es e un descriptor de despliegue skeleton que rnuestra 10s elementos anteriores:

< ! DOCTYPE

Web-app

PUBLIC

'-//Sun

2.3//EN'.

'http://java.sun.com/dtd/Web-app

Microsystems, Inc. / / D T D W e b Application 2.3.dtd'>

<!D e c l a r e f i l t e r d e f i n i t i o r ~ s -> <filter> <filter-name> Name of t h e filter </filter-name> <filter-class> Class name for the filter </filter-class> <init-param> <param-name> N a m e o f t h e p a r a m e t e r </param-name> <param-value> Value of the parameter </param-value> </init-param> < ! - M o r e i n i t i a l i z a t i o n p a r a m e t e r s -> </filter>

Filtros Dara a~licaciones Web

<!-

Map f i l t e r s t o r e q u e s t s -> <filter-mapping> < f i l t e r - n a m e > Name o f t h e f i l t e r < / f i l t e r - n a m e > < u r l - p a t t e r n > URL p a t t e r n < / u r l - p a t t e r n > </filter-mapping>

<!-

Declare

s e r v l e t s ->

</Web-app>

La aplicacion de chat con filtros


Consideremos ahora ciertas mejoras en la aplicaci6n de chat que desarrollamos en el capitulo anterior y veamos c6mo 10s filtros pueden ser utilizados para implementar estas mejoras:

O Registro de mensajes Es habitual registrar mensajes de chat en una fuente de datos persistente con prop6sitos de control. i C 6 m o implementamos un registro de este tip0 para todos 10s mensajes de chat? O Moderaci6n de mensajes iC6mo podemos implementar un sistema de moderaci6n de mensajes en el que 10s sistemas que contengan palabras desagradables u ofensivas puedan ser detectados? Cuando la aplicaci6n recibe mensajes que contengan ciertas palabras, podemos reemplazar el mensaje con un mensaje estindar de advertencia.
U n mod0 de implementar estas funciones es alterando la clase C h a t R o o m s e r v l e t :

o Para registrar cada mensaje en una fuente de datos persistente como una base de datos
0 Para examinar cada mensaje en busca de palabras desagradables y reemplazar 10s mensajes que

contengan tales palabras por un mensaje de advertencia Sin embargo, esto supone modificar ~ h a t ~ o o m ~ e r v afiadiendole let mayor complejidad. Ademis, un mecanismo asi n o seria declarativo. En su lugar, consideremos el uso de filtros para implementar estas funciones de tal mod0 que:
0

Podamos implementar estas funciones in modificar el c6digo existente

O Podamos convertir estas funciones en declarativas de mod0 que puedan ser desplegadas o eliminadas sin afectar a la verdadera aplicaci6n de chat
En esta seccibn, desarrollaremos dos filtros, uno para el registro de mensajes y el segundo para la moderation de mensajes. Estos filtros estin representados a continuaci6n:

Capitulo 8

Registro de mensajes
Consideremos una tabla de base de datos con columnas PROFILE-NAME, ROOM-NAME, MESSAGE y TIME-STAMP para registrar cada mensaje de chat a medida que van siendo recibidos por la aplicacibn de chat. De estas columnas, la cuarta columna indica la hora en el que el mensaje ha sido recibido por el contenedor que alberga la aplicacibn. Cree una nueva base de datos que seri utilizada para albergar la tabla para la aplicaci6n de chat. Cree la MESSAGE-LOG con las siguientes instrucciones SQL CREATE:
CREATE TABLE MESSAGE LOG (MESSAGE I D PROFILE NAME ROOM NAME MESSAGE TIME-STAMP INT DEFAULT AUTOINCREMENT INITIAL 1 INCREMENT 1 NOT NULL, VARCHAR ( 20). VARCHAR(20). VARCHAR(100), TIMESTAMP);

Ahora podemos escribir un filtro para extraer el nombre del perfil del usuario, el nombre de la sala de chat

y el mensaje de chat a partir de la solicitud o de la sesibn. Introduzca el siguiente filtro:


import import import import import import import import
javax.servlet.Serv1etRequest; j avax. servlet. ServletRespor~se; javax.servlet.Serv1etException; javax.servlet. Filter; javax. servlet. EilterChaln; javax.servlet. Filterconfig; javax.serv1et.http.HttpSession; javax.servlet.http.HttpServ1etRequest;

import j ava. io. IOException; import import import import import import import import java.sq1.Connection; j ava. sql. DriverManager; java. sql. Preparedstatement; j ava. sql . SQLException; java.sql.Timestamp; javax.sql.DataSource; j avax.narning. InitialContext; j avax. naming. NamingExcept ion;
[
/

public class Message1,ogFilter implements Filter

public void doFilter(Serv1etRequest request, ServletResponse response, Filterchain chain) throws IOException, ServletException {

Filtros para aplicaciones Web


/ / Invocar el siguiente filtro chain.doFilter (request, response) ;
/ / Obtener la sesihn HttpSession session
=

((HttpServletRequest) request).getSession();

/ / Obtener el mensaje d e chat a partir d e la solicitud String message = request .getparameter ("msg") ;

/ / Obtener el r~ombre del perfil a partir d e la sesihn String profileNarne = ( S t r i n g ) session.getAttribute ("profileNamee') ; / / Obtener el nombre d e la sala a partir d e la sesihn String roomName = (String) session.getAttribute ("roomNarne" ) ;
/ / Crear una estampilla d e tiempo Timestamp timestamp = new Timestamp (System.currentTimeMi11is (
) ) ;

/ / Obtener una conexi6n a la base d e datos Connection connection = null; String insertStatementStr = "INSERT INTO MESSAGE LOG " + "(PROFILE NAME, ROOM NAME, MESSAGE, TIME STAMP) VALUES ( ? ,

?,

?,

?)";

InitialContext initial = new InitialContext ( ) ; DataSource d s = ( DataSource) initial. lookup ( " jdbc/chatV') ; connection = ds. getConnection ( ) ; PreparedStatement i nsertStatement = connectior~.prepareStatement(ir~sertStatementStr) ; insertStatement .setString ( 1 , profileName) ; insertStatement .setString ( 2 , roomName); insertstatement .setStri ng (3, message); insertStatement.setTimestamp(4, timestamp); insertStatement. executeupdate ( j ;

1
j
I

catch (NamingException ne) { throw n e w ServletException ( " JNDI error", n e ) ; catch (SQLException sqle) { throw new ServletException("Database error", sqle);

finally 1 if (cor~nection ! = null) 1 try I connection.close ( ) ; j catch (SQLException sqle) 1 1


I
1

public void destroy() ( 1

Durante la inicializaci6n, este filtro lee detalles de la base de datos desde el descriptor de despliegue. Cuando el filtro es invocado mediante el metodo d o F i l t e r ( ) , extrae la informaci6n requerida de la solicitud y la sesibn, e inserta estos datos en la MESS MESSAGE-LOG. Observe que, en este filtro, la primera instrucci6n del mitodo d o F i l t e r ( ) es una llamada a1 mitodo d o F i l t e r ( ) de la cadena de filtro. Esto es asiparapermitir a ~ h a t ~ o o m ~ e r v que l eprocese t la primera solicitud, lo que significa que el registro tiene lugar despuis de que el resto de la cadena sea procesada. C o m o veremos mis adelante, en el descriptor de despliegue e l ~ e s s a g e ~ o g ~ i es l t el ed r t i m o filtro y

Capitulo 8
se aplica a todas las solicitudes a la sala de chat. Consecuentemente, cuando un usuario de chat envia un mensaje a una sala de chat, el filtro deja primero que C h a t R o o m S e r l v e t realice su trabajo (que es ti elr invoca el preparar la respuesta). Esto es asi porque, antes de registrar el mensaje, M e s s a g e ~ o g ~ siguiente filtro invocando el metodo d o F i l t e r ( ) . Esto provoca q u e M e s s a g e L o g F i l t e r invoque a C h a t R o o m s e r v l e t . Una vez hecho esto, el control vuehe a M e s s a g e L o g F i l t e r , que entonces registra el mensaje en la base de datos. El resto de este filtro utiliza JDBC para realizar una funci6n INSERT en la tabla d e m e s s a g e - l o g de nuestra base de datos.

Moderacion de mensajes
Consideremos ahora la moderacidn de mensajes que requiere reemplazar mensajes que contengan palabras ofensivas o desagradables por una advertencia. Asumamos que las palabras consideradas ofensivas o desagradables proceden de un archivo de texto. Para moderar 10s mensajes, estos son 10s pasos requeridos:
O Leer la lista de palabras del archivo de texto.
0

Examinar cada mensaje que entre en una sala de chat. Si un mensaje contiene una de las palabras que aparecen en el archivo de texto, reemplazarlo con una advertencia estindar.

Ambos pasos deben tener lugar antes de que C h a t R o o m S e r v l e t sea invocado de modo que, para cuando 10s mensajes Sean lanzados a la sala de chat y posteriormente leidos por 10s miembros del chat, 10s mensajes ya deben estar moderados. Lo mismo sucede con el registro.
ilte implementar r estas funciones. Durante la Considere el f i l t r o ~ e s s a ~ e ~ o d e r a t o r ~para inicializaci6n, este filtro puede leer la lista de palabras y durante el metodo d o F i 1t e r ( ) ,el filtro puede examinar el mensaje de chat y modificarlo si es preciso.

Antes de que veamos el cddigo completado, analizaremos algunos de 10s metodos importantes implicados. Implementemos primero el metodo i n i t ( ) :
public void init(Fi1terConfig config) throws ServletException { try I String fileName = config.getInitParameter("moderated words file"); / / Leer el archivo que contiene palabras para su moderaci6i-1 Inputstream is = corlfig.getServletContext ( ) .getResourceAsStream(fi1eName); BufferedReader reader = new BufferedReaderi new InputStreamReader (is)) ; wordList = new A r r a y L i s t O ; while(true) I String word = reader. readline ( ) ; if(word == null ) { break;

I
wordList.add(word.toLowerCase()) ;

I
reader.close(); warningMessage = config.getInitParameter ("warnir~gmessage") ; if (warningMessage == null) 1 warningMessage = Message restricted";
' I t t *

1 catch(I0Exception ie) I

Filtros para aplicaciones Web


ie.printStackTrace ( ) ; throw n e w ServletException("Error catch(Exception e ) { e.printStackTrace ( ) ; reading moderated words.txtW);

Este metodo abre un archivo cuyo nombre esti especificado como parimetro de inicializaci6n para este filtro. El filtro abre este archivo utilizando el metodo g e t s e r v l e t c o n t e x t ( ) del objeto F i l t e r C o n f i g . Utilizando este metodo, podemos abrir archivos y otros recursos disponibles en el interior de la aplicaci6n Web. El metodo i n i t ( ) lee las palabras y las almacena en una lista. Este metodo tambikn lee un mensaje estindar de advertencia mediante otro parimetro de inicializaci6n. Consideremos ahora el metodo d o F i l t e r ( ) :
public void doFilter(Serv1etRequest request, ServletResponse response, Filterchain c h a i n ) throws IOException, ServletException { String message = ( (HttpServletRequest) request) .getparameter ("msg" ) ; if (message ! = null) [ boolean setwarning = false; for(int i = 0; i < wordList.size(); it+) [ if (message.toLowerCase().indexof ( ( S t r i n g wordList.get (i)) ! = - 1 ) { setwarning = true; break;

1 1
if(setWarning1 { message = warningMessage; / / ;C6mo cambiamos el parimetro de solicitud? Pronto lo veremos

1 1
/ / Invocar el siguiente filtro. chain.doFilter(request, response);
1

Este metodo extrae el mensaje de la solicitud entrante y lo examina para comprobar si alguna de las palabras de la lista creada anteriormente se encuentra en el mensaje. Si es asi, el metodo configura un booleansetWarning entrue. En la segunda parte de este metodo, si s e t w a r n i n g devuelve t r u e , este metodo debe cambiar el mensaje en la solicitud por el mensaje de advertencia. Sin embargo, n o existe un metodo s e t P a r a m e t e r ( ) en el objeto solicitud con el que podamos reemplazar el mensaje original por el mensaje de advertencia. Para superar este obsticulo, consideremos dos factores:
0 Podemos utilizar el metodo s e t A t t r i b u t e ( ) sobre el objeto solicitud para fijar el mensaje

modificado en la solicitud. Aunque ChatRoomSe r v l e t n o puede extraer este parimetro via g e t P a r a m e t e r ( ) ,este es el 6nico mod0 en que podemos afiadir datos a una solicitud. Alternativamente, podemos almacenar el mensaje de advertencia en la sesi6n pero, para que lo lea C h a t R o o m S e r v l e t , seripreciso que m o d i f i q u e m o s ~ h a t ~ o o m rv ~le et.
0

La l l a m a d a d o ~ i l t e (r) del o b j e t o ~ i l t e r c h a i requiere n a 10s objetos solicitud y respuesta como argumentos. Instado por esta llamada, el contenedor i n v o c a , ~ h a t ~ o o m ~ e r v con let 10s objetos solicitud y respuesta pasados.

Puesto que el s e r v l e t ~ h a t ~ o o m s e r v lie ntv o c a g e t ~ a r a m e t e (r) paraextraerel mensaje dela solicitud y puesto que el filtro envia 10s objetos solicitud y respuesta a1 servlet a traves de la cadena de

Capitulo 8
filtro, podemos sustituir el objeto solicitud original por un nuevo objeto solicitud. Podemos implementar esta nueva clase de solicitud para devolver el mensaje modificado cuando sea invocado el mitodo getparameter 0 . Consideremos ahora una clase de solicitud de este tipo:
import j a v a x . s e r v l e t . h t t p . H t t ~ ~ S e r v l e t R e q ~ ~ e s t ; import javax.servlet.http.HttpServ1etRequestVJrapper; import java.util.List; public class ModeratedRequest extends HttpServletRequestWrapper
{

public ModeratedRequest(HttpServ1etRequest request, List rnoderatedparameters) { super(request); t h i s . m ~ d e r a t e d P a r a m e t e r s = rnoderatedparameters;

1
public String getParameter(Strir1q parameterName) { / / Si este pardmetro es uno de los parametros moderados, / / es un atributo. Si no, es un pardmetro de solicitud i E ( m o d e r a t e d P a r a m e t e r s . ~ ~ r ~ t a i r ~ s ( p a r a m e t e r N a m{e ) ) return ( S t r i n g ) super. getAttribute (parameterblame) ; 1 else ( return super.getParameter(parameterName);

Estaclaseampliaj avax. servlet .h t t p . ~ t t ~ ~ e r v l e t ~ e q u e s t ~ r a ~ ~ e r ~ u e ~ r o ~ o r c i o n implementaci6n de la interfaz j avax . servlet .h t t p .HttpServletReques t.Elconstructorde esta clase toma dos parimetros: un objeto HttpServletRequest y una lista que contiene atributos a 10s que se puede acceder como parimetros de solicitud. La clase javax. servlet .http.~ t t ~ ~ e r v l e t ~ e q u e s t ~ r a p p e r i m ~ l e m e n t a ~ a i n t e r f a z j avax servlet .http. HttpServletRequest. Laimplementaci6nutilizaelobjeto javax. servlet .http.HttpServletRequest provistodurante~aconstruccionpara~a implementaci6n real. Fundamentalmente delega todas las llamadas de mitodo en el objeto proporcionado.

El metodo get parameter ( ) de esta clase delega la llamadaen 10s mktodos getAttribute ( ) o get P a r a m e t e r ( ) de la super clase basada en el nombre del parimetro. Si el nombre del parimetro esti contenido en la lista de parimetros especificada en el constructor, este mCtodo delega la llamada en el metodo ge tAt t r ibut e ( ) . Por ejemplo, si incluimos el nombre del parimetro "ms g " en la lista, una llamada a getparameter ( "msg" ) tendria como resultado una llamada a1 metodo getAttribute ("msg") delasuperclase. Utilizando esta tkcnica, podemos cambiar el metodo doFilter
()

del siguiente modo:

if ( s e t W a r n i n q ) { message = warningMessage; request. setAttribut-e("msg", message) ; request = n e w ModeratedRequest( (HttpServletRequest) request, moderatedparameters) ;

I
Este c6digo sustituye a1 objeto original solicitud por el objeto solicitud de adaptaci6n proporcionando la misma funcionalidad except0 por el metodo getparameter ( ) . En este c6dig0, rnoderatedparameters es una lista que contiene la palabra "msg" creada en el mitodo init ( ) .

Filtros Dara a~licaciones Web


~ s t es e el listado cornpleto del filtro:
import import import import import import import j avax. s e r v l e t . Filter; javax.servlet. Filterchair); javax.servlet. FilterCarlfig; javax.servlet.ServletExce~~tion; javax.servlet.ServletRequest; j avax. servlet. ServletRespcr1se; javax.servlet.http.HttpServ1etRequest;

import j ava. io. InputStream; import j ava. io. InputStreamReader; import j ava. io. BufferedReader; import j ava. io. IOException; import j a v a . u t i l . A r r a y L i s t ; public class MessageModeratorFilter String protucol; ArrayList wcrdlist; ArrayList rnoderatedparameters; String warrtingMessage; pub1 ic void init ( FilterConf iq conf ig) throws ServletException { try i String fileName = config.getInitParameter("moderated words file"); / / Leer el archivo que contiene las palahras para la moderaci6n InputStream is = cor~fig.getServletCor~text().getResourceAsStream(fileName); BufferedReader reader = new Buff eredReader (new InputStreamReader ( i s ) ) ; wordList = new ArrayList ( ) ; whileitrue) String word = reader. readline I ) ; if (word = = null) { break; implements Filter
{

I
wordList.add(word.toLowerCase()) ;
\

/ / Cbtener el archivo de advertencia. Si no se encuentra, ~ltilirarm n p'r clefectr, warningMessage = confiq.getInitParameter ("warr~ir~g message"); if (warningMessage == null ) { warningMessage = Message restricted";
" + + +

I
1

rnoderatedparameters = n e w ArrayList ( ) ; m o d e r a t e d p a r a m e t e r s . add ( " m s g g g ; ) c a t ~ h ( 1 O E z c e p t i o n ie) { ie.printStackTrace(); throw new ServletException ( " E r r o r reading moderate words. txt" ) ; catch(Exception e ) { e .printStackTrace( ) ;

I
public void doFilter(Serv1etRequest request, ServletResponse response, Filterchain c h a i n ) throws IOException, ServletExcepticn I / / Obtener el mensaje a partir d e la solicitud. String message = ( (HttpServletRequest ) request) . getparameter ( " m s g " );

Capitulo 8
/ / Comprobar si el merlsaj e tier~e palabras desagradables. if (message ! = null) { boolean setWarninq = false; for(int i = 0; i < wordList.size0; i++) { if(message. toLowerCase() . indexof ( ( S t r i n g wordList.get ( i )) setwarning = true; break;

! = -1)

I
1
/ / Si es asi, reernplazarlo por el mensaje con la advertencia. if (setwarning) [ message = warningMessage; request. setAttribute ("msg", message) ; request = new ModeratedRequest((HttpServ1etRequest) request, moderatedparameters);
)

I
/ / Invocar el siguiente filtro chain.doFilter (request, response) ;

I
public void destroy() 1 j

Descriptor de despliegue
El siguiente paso es mqdificar el descriptor de despliegue para afiadir las declaraciones de filtro y las asociaciones de filtro. Este es el descriptor de despliegue modificado:

< ! DOCTYPE

Web-app PUBLIC "-//Sun Microsysterns, Inc. //DTD Web Applicatior~ 2. 3//ENt' "http://java.sun.com/jZee/dtds/Web-app-2-3.dtd1'>

Filtros para aplicaciones Web


<filter> <filter-r~ame>MessageModeratorFilter</filter-r~ame> <display-name>MessageModeratorFi1ter</display-r~ame> <filter-class>MessageModeratorFilter</filter-class> <init-param> <param-name>moderated words file</param-name> <param-value>moderated words.txt</param-value> </ init-param> <init-param> <param-name>warning message</param-name> <param-value>*** Messaqe filtered by the moderator.</param-value> </init-param> </filter>

Asirnisrno, Cree un archivo de texto Ilarnado moderated-words .txt.Introduzca palabras en este archivo escribiendo cada palabra en una linea nueva. Corno dernostraci6n, introduzca las siguientes palabras en este archivo:
bad pain free

Tarnbitn necesitarnos el archivo index. html para la pantalla inicial:

<p>Click <a h r e f = " / c h a t / s e r v l e t / c h a t A d m i r ~ " > h e r e ~ / a > to administer chat rooms.</p>

Capitulo 8
<p>Cllck <a href="/chat/servlet/listRoorns">here</a> chat rooms, and to join a chat roorn.</p> to view current

Despliegue
Para desplegar esta aplicacion, seguimos el mismo proceso anterior. Empezamos creando el archivo WAR ( c h a t .war). Asegurese de que tiene 10s siguientes archivos en las siguientes ubicaciones:
chat/ l n d e x . htrnl moderated words.txt WEB-INF/ Web. xrnl classes/ ChatAdrnlnServlet.slass ChatEntry. class ChatRoorn. class ChatRoomServl et .class LlstRoornsSe~vlet.clasMessageLogFllter.class MessageModeratorFllter.class ModeratedRequest.class

Para crear el archivo WAR, utilizaremos el siguiente comando j a r :


j a r -svf chat .war index.htrn1 n ~ o d e r a t e d ~ w o r d s txt . WEB-INF

De nuevo iniciamos el servidor J2EE y la herramienta de despliegue de la aplicacibn. Esta vez, Cree una nueva aplicaci6n llamada c h a t . e a r . Atiada c h a t . w a r a la apkaci6n y ya estamos de nuevo preparados para desplegar la aplicacion. En la primera pantalla, s610 es necesario que comprobemos si estamos desplegando la aplicaci6n correcta. En la siguiente pantalla, necesitamos proporcionar el context0 que utilizaremos para navegar hasta nuestra aplicacion. Configurela en c h a t . Proceda hasta la pantalla final y seleccione F i n i s h (Finalizar) para desplegar la aplicacion en el servidor. Antes de que pueda ejecutar la aplicaci6n, tambien necesitamos crear la fuente de datos j d b c / c h a t que apunte hacia nuestra base datos recien creada. Esto puede hacerse utilizando la ventana s e r v e r C o n f i g u r a t i o n (Configuration del servidor). Reinicie el servidor para cargar la nueva fuente de datos y asegGrese de que la base de datos se esta ejecutando. Para cornprobar la aplicaci6n, introduzca http://localhost:8000/chat/index.html. Entonces, debe ver la siguiente pantalla:

Filtros para aplicaciones Web

IiI Archwo

E d c ~ h Ver

Fwer~tor Herrwlmntas

I R I

11 I

Chat Application
Click h.rc to admuuter chat moms. Click here to wiew current chat rooms, and to join a chat room.

dlI
II
Local

Lkto

rr

Cuando un mensaje es enviado a una sala de chat moderada por el filtro, vemos la siguiente pantalla:

Room: General Identity: Robert Robert . Messqc filtered Gy tlie moderatnr

Enter your message:

Send Messsae

Chat con registro y moderacion


Cuando iniciamos una aplicaci6n y comenzamos a enviar mensajes de chat, sucede lo siguiente:
1.

El descriptor d e despliegue especifica /chat como la representacibn para ambos filtros. Asi, todas
!as solicitudes representadas en http://localhost:800O/chat/servlet/chatAdrnin provocan que el contenedor invoque estos filtros.

2. Puesto queMes s a g e M o d e r a t o r F i l t e r es representado en la ruta anterior, el contenedor

invoca p r i m e r o M e s s a g e M o d e r a t o r F i l t e r . Este filtro busca palabras desagradables/ofensivas

y cuando aparecen tales palabras, afiade un atributo de solicitud llamado "ms g " y crea un objeto M o d e r a t e d R e q u e s t . Este filtro invoca entonces d o F i l t e r ( ) en el objeto F i l t e r c h a i n .
3. El contenedor invoca entonces Mes s a g e L o g F i l t e r , puesto que el siguiente representado. Sin

embargo, antes de registrar el mensaje, M e s s a g e L o g F i l t e r invoca primer0 el mitodo doFilter () enelobjeto~ilter~hain.


4. Puesto que no hay mas filtros representado para esta solicitud, el contenedor invoca

ChatRoomServlet.
5. C h a t R o o m S e r v l e t lee la solicitud, creando una respuesta como es habitual.
6. El control regresa entonces a M e s s a g e L o g F i l t e r . El filtro procede a registrar el mensaje y

despuks vuelve.
7 . El control regresa entonces a M e s s a g e M o d e r a t o r F i l t e r . Este filtro ya ha rnoderado el

mensaje y vuelve. Los mismos eventos tienen lugar para cada rnensaje enviado a una sala de chat. Consideremos ahora ciertas variaciones:
0 Para eliminar la moderaci6n de rnensaje, sirnplemente elirnine la representacih para MessageModeratorFilter en el descriptor de despliegue. 0 Para eliminar el registro de rnensajes, sirnplernente elimine la correspondiente representacih del descriptor de despliegue. 0 C o n el c6digo anterior, 10s mensajes moderados serin registrados en lugar del mensaje original. <Ysi en cambio desea registrar el mensaje original antes de la rnoderaci6n? Con este objetivo, podernos r n o d i f i c a r ~ e s s a g e L o g F i l t e para r leer el mensaje utilizando el rnktodo g e t A t t r i b u t e ( ) e n l u g a r d e g e t ~ a r a m e t e (r ) .
LI TambiCn podernos perfeccionar este ejernplo con el objetivo de reernplazar palabras indeseables con ,,::.::.::.,,

en lugar de sustituir el rnensaje cornpleto.

Puede probar estas variaciones por su cuenta corno un ejercicio complementario.

Los filtros proporcionan un rnecanisrno rnuy util para alterar programiticamente el mod0 en que el contenedor sirve a 10s recursos Web. El rnecanisrno de filtro es independiente del tip0 de recurso. Se aplica por igual a recursos dinimicos corno servlets o piginas JSP, y a recursos estiticos como archivos HTML, imigenes, etc. Los ejernplos de este capitulo han ilustrado dos puntos clave:

O Podemos introducir uno o mas filtros en el proceso solicitud-respuesta.

o U n filtro puede rnodificar el entorno para servlets y piginas JSP. Corno hernos ilustrado con el
M e s s a g e M o d e r a t o r F i l t e r , podemos crear nuevos objetos solicitud, respuesta o incluso de sesi6n para servlets o piginas JSP. Esta funci6n nos abre diversas posibilidades para construir aplicaciones Web rnis inteligentes.

Filtros Dara aplicaciones Web


Cuando pretenda desarrollar sus propias aplicaciones Web, considere si su funcionalidad r e h e las condiciones para implementa filtros. Tambien puede tener en cuenta 10s filtros cuando afiada nuevas caracteristicas a aplicaciones Web existentes. En general, si encuentra cierta 16gica comun a uno o mis senlet/pigina JSP, o si desea incluir comportamiento dinimico antes de invocar contenido estitico, considere el uso de filtros. Los filtros proporcionan un mecanismo declarativo y, por lo tanto, libremente acoplado con el que afiadir Ctiles funciones. En el siguiente capitulo, completaremos nuestra exploraci6n de la especificaci6n de Senlet y analizaremos algunos otros temas implicados en el desarrollo de aplicaciones Web.

y empaquetado
Los procesos de disefio y desarrollo en aplicaciones J2EE estin claramente separados de 10s de despliegue y empaquetado. La arquitectura J2EE consigue esta separacion fomentando la construcci6n de componentes libremente relacionados y reajustables. Esto permite que 10s componentes scan reutilizables, que a su vez permite que la configuration del periodo de ejecucion sea mis flexible. En este capitulo, comprenderemos a hacer uso de las funciones de despliegue y empaquetado proporcionadas por la arquitectura de contenedor de servlet. Las tCcnicas y estrategias que aprendemos nos proporcionarin un mayor grado de flexibilidad que podremos introducir en las aplicaciones. Concretamente, examinaremos:
0

La base 16gica que subyace a la estructura de las aplicaciones Web que hemos visto en capitulos anteriores

O Corn0 asociar solicitudes

HTTP a diferentes componentes de aplicacion Web

C6mo 10s modelos de autentificacion para aplicaciones Web pueden ser conectados a aplicaciones Web sin tener que implementar autentificacidn en el nivel de la aplicaci6n El uso del descriptor de despliegue para configurar varios aspectos de una aplicaci6n Web, incluido la inicializacion y arranque de servlet, plazos limite de sesion, asociaciones MIME, archivos de bienvenida y manejo de errores.

Estructura de aplicacion Web


Una aplicaci6n Web es una coleccion de diferentes tipos de archivos. Una tipica aplicacion Web puede incluir, entre otros elementos:

Capitulo 9

O Piginas HTML O Imigenes

0 U n descriptor de despliegue y otros archivos de configuracion

El concept0 de una aplicaci6n Web fue introducido en la version 2.2 de la especificaci6n Java Sewlet. Una aplicacih Web esti organizada con una jerarquia estructurada de directorios, con tipos determinados tipos de archivos almacenados en determinados directorios, Estos directorios pueden entonces ser empaquetados en un archivo de aplicacion Web, Web application archive (WAR).

Estructura de directorio
La estructura de directorio de una aplicacih Web tiene dos partes:

O U n directorio llamado WEB- INF que contiene 10s recursos que no deben ser directamente descargados a un cliente; este directorio es privado (el cliente no tiene acceso direct0 a 10s N ' ? contiene habitualmente recursos dinimicos archivos de este directorio). El directorio WEB- I tales como sewlets, asi como archivos de configuracion. O U n directorio que contiene aquellos recursos destinados a ser de disposici6n p6blica. ~ s t incluye e todos 10s subdirectorios de este directorio excepto, por supuesto, el directorio privado WEB-INF. Este directorio contiene normalmente recursos estiticos como archivos HTML y de imagen.
Por ejemplo, una aplicaci6n Web podria tener esta estructura de directorio:
rnyWebApp\ index.htm1 login.j s p 404NotFound. htrnl images\ logo.gi f banner.gif literature\ s u m m a r y .j s p Y2001AnnualReport.pdf Y2001PresidentAddress.pdf WEB-IN\ Web. xrnl classes\ ShoppingCart.class Catalog.class CheckOut.slass lib\ dblibrary. j a r xrnlTools.j a r

En la estructura de este directorio, myWebApp es el directorio raiz de la aplicacidn Web. 10s recursos publicos de esta aplicacion Web son 10s dos archivos HTML, index.html y 404NotFound.html,y el archivo JSP, login. j sp y 10s archivos contenidos en 10s subdirectorios images y literature, logo. gif,banner. gif y Y2001AnnualReport .pdf.Los otros archivos, contenidos enel directorio WEB- INF,son recursos que so10 son accesibles para el contenedor. U n recurso publico es cualquier archivo que sea accesible para el cliente de la aplicaci6n Web. Los tipicos recursos p6blicos incluyen:

Despliegue Web, autentificacion y empaquetado


0 Documentos HTML, XML y JSP 0 Archivos de imagen, sonido y video 0 Applets Java (clases y archivos JAR que contengan applets) 0 Documentos de Microsoft Office (Word, Excel, etc.)

Los navegadores cliente pueden descargar estos recursos sin alterar y transmitirlos segdn sea preciso. Por ejemplo, cuando una pdgina HTML inchye una etiqueta <APPLET> que hace referencia a un archivo JAR, el contenedor Web entrega el archivo JAR a1 navegador cliente sin alterar.

Aunque las pa'ginas JSP esta'n incluidas como recursos priblicos en una aplicaci6n Web, el contendor no las muestra directamente a 10s clientes. El contenedor convierte automa'ticamente las pa'ginas JSP en servlets. El servlet es entonces compilado e invocado para generar la respuesta para el cliente. Sin embargo, puesto que una pa'gina JSP es a menudo considerada ma's afin a un documento HTML que a una clase Java, las pa'ginas JSP tambie'n esta'n incluidas en 10s recursos priblicos.
Normalmente, el contenedor lee el recurso estdtico del sistema de archivos y escribe 10s contenidos directamente a la conexidn de red. La interpretacidn del contenido de estos recursos es responsabilidad del navegador cliente. Para ayudar a1 navegador a reproducir el archivo correctamente, el contenedor envia el tip0 MIME del archivo. Estos tipos MIME pueden ser configurados en el descriptor de despliegue de la aplicacion Web. Por supuesto, hay ciertos recursos que 10s clientes no deben descargar directamente. ~ s t o pueden s ser archivos que el cliente no debe ver, como archivos de configuracidn, o pueden ser archivos sobre 10s que el contenedor debe realizar algGn tip0 de procesamiento antes de enviar la respuesta a1 cliente, como servlets. Estos recursos privados son almacenados en el directorio WEB-INF o en sus subdirectorio~. Los tipos de recursos que 10s clientes n o deben descargar directamente incluyen:
0 Servlets. Estos componentes incluyen bgica de aplicacidn y posiblemente acceso a otros recursos como bases de datos

Cualquier otro archivo de la aplicacion Web a1 que 10s servlets puedan acceder directamente
0 Recursos destinados a la ejecucidn o uso en el lado servidor, como archivos de clase Java y archivos JAR para clases utilizadas por nuestros servlets
U Archivos temporales creados por sus aplicaciones

0 Descriptores de despliegue y cualquier otro archivo de configuraci6n

Estos archivos son privados y, como tales, so10 son accesibles para su propia aplicacidn Web y para el contenedor. Para acomodar recursos privados, el contenedor Web requiere que el directorio WEB-INF estk presente en su aplicacidn. Si su aplicacidn Web no contiene este directorio, no funcionard. WEB-INF incluye:
0 U n archivo Web. xrnl. ~ s t es e el archivo del descriptor de despliegue.

U n subdirectorio llamado classes. Este directorio es utilizado para almacenar archivos de clase Java de lado servidor como servlets y otras clases ayudantes, estructurados de acuerdo con las reglas habituales de empaquetado de Java.
0 U n subdirectorio lib para contener 10s archivos JAR utilizados por la aplicacion Web.

Esta estructura tiene varias ventajas. El beneficio mis significativo es que varias aplicaciones pueden coexistir en el mismo contenedor Web sin ningdn conflicto. Cada aplicacidn existe en una "caja de arena"; 10s recursos pGblicos y privados de una aplicacidn son independientes de cualquier otra aplicaci6n que el

Capitulo 9
contenedor pueda estar ejecutando. Aunque este modelo parece muy intuitivo en aplicaciones autdnomas, no estuvo disponible en el servidor hasta que se introdujeron las aplicaciones Web en J2EE. Cada aplicacidn Web debe ser gestionada de forma independiente a todas las demis aplicaciones que pueden estar ejecutindose en el contendor, como hemos visto en 10s ejemplos de capitulos anteriores. Cuando se atiade una nueva aplicacibn a1 servidor J2EE, podemos sencillamente ahadir el adecuado c o n t e x t r o o t en el d e p l o y t o o l de la Implementaci6n de Referencia (como hemos descrito en 10s capitulos previos), sin afectar a ninguna de las otras aplicaciones.

En versiones anteriores de contenedores W e b (llamadas entonces "motores" servlet), hubie'ramos mantenido normalmente todos nuestros servlets en u n directorio / s e r v l e t s y hubie'ramos mantenido todos 10s recursos ptiblicos en el documento raiz del servidor Web. Esto equivale a tener una aplicacidn grande que combine todos 10s servlets. Agrupar todos 10s recursos ptiblicos bajo el documento raiz del servidor Web de este modo plantea restricciones de mantenimiento del mismo modo que u n cambio en u n servlet puede tener efectos indeseados en otras aplicaciones.
Otra ventaja de organizar 10s recursos de este mod0 es que el contenedor sabe d6nde buscar clases. El cargador de clases del contenedor comprueba automiticamente el directorio classes, asi como 10s archivos JAR del directorio l i b . Esto significa que no necesita ahadir estas clases y archivos JAR explicitamente a CLASS PATH.Recuerde que mientras desplegamos las aplicaciones de muestra en capitulos anteriores, no necesitamos cambiar las configuraciones de CLASSPATH porque el contenedor podia localizar y cargar las clases del servlet automiticamente. El directorio publico de una aplicacidn Web es similar a1 directorio raiz de documentos de un servidor Web convencional. Al ubicar 10s archivos en un servidor Web convencional, el contenido publico se mantiene en cada aplicacidn Web en el directorio raiz de la aplicacidn. La diferencia entre un servidor Web convencional y el contenedor Web estriba en que cada aplicacidn Web tiene su propia raiz de documentos. Existe otra ramificacidn para esta organizaci6n. De acuerdo con la especificaci6n del servlet, un contenedor deber cargar clases/archivos JAR de cada aplicacion Web utilizando un cargador de clases diferente. Es por esta razdn por lo que servlets, paginas JSP y otras clases que forman parte de una aplicacidn Web no pueden ver clases en otras aplicaciones y, por lo tanto, no pueden compartir variables estiticas o clases semifallo, por ejemplo. Asi, incluso si despliega la misma aplicacion Web dos veces (cada una asociada a un URL diferente), en lo que se refiere a1 contenedor son dos aplicaciones completamente diferentes. Tales aplicaciones no pueden compartir information. Como resultado, 10s contenedores Web crean una particion virtual de aplicaciones Web dentro del contenedor.

Ficheros en archivo Web


Los diversos directorios y archivos que componen una aplicacidn Web pueden ser empaquetados en un fichero de archivo de aplicaci6n Web (WAR). Este proceso es similar a1 empaquetado de 10s archivos de clase Java en archivos JAR. El propdsito de este empaquetado es el mismo: proporcionar un mod0 simplificado de distribuir archivos de clase Java y sus recursos relacionados. Los archivos WAR pueden crearse utilizando la misma herramienta j a r que se utiliza para crear archivos JAR. Una aplicacidn Web puede ser desplegada como un archivo WAR, en vez de la coleccidn sin empaquetar de directorios y archivos. Consideremos la aplicacidn de chat desarrollada anteriormente. Empaquetaremos esta aplicacidn en un archivo WAR y desplegaremos el archivo WAR resultante en el contenedor en lugar de 10s directorios y archivos expandidos. La aplicacidn de chat fue guardada en %BOOK-HOME% \cHO 7 \ c h a t \. Abra una invitation de comando, cambie el directorio en funcionamiento a este directorio y ejecute el siguiente comando:

Despliegue Web, autentificacion y empaquetado

Este comando ernpaqueta todos 10s contenidos bajo este directorio, incluido 10s subdirectorios, en un fichero en archivo llarnado chat .war. Hernos utilizado dos opciones de linea de cornando:
U La opcidn -c para crear un nuevo archivo

u Ln opcidn -f para especificar el nombre del fichero en archivo de destino


Estos dos comandos son utilizados juntos corno -cf. Si la opcidn verbose es especificada, utilizando -v, 10s nombres de 10s archivos y directorios incluidos en el archivo saldrin en pantalla. Puede utilizar el siguiente cornando para ver 10s contenidos de un archivo WAR:

Este cornando enumera 10s contenidos del archivo WAR:

En lugar de incluir todos 10s contenidos, puede seleccionar archivos y subdirectorios individuales niientras crea archivos WAR. Rernitase a la docurnentacidn JDK y encontrari una lista cornpleta de estas opciones de linea de coniando para la herramienta jar. Puede tambikn utilizar herramientas de manipulacibn de archivo ZIP estindar corno WinZip para crear y rnanipular archivos WAR. Observe que la herrarnienta jar crea automiticarnente el subdirectorio META- I N F y sus contenidos.

Desplegar un archivo WAR


Un servidor que se ajuste a JSP 1.1 desplegarl automiticamente una aplicacidn ernpaquetada corno archivo WAR, siempre que la ubicacidn del archivo WAR estC indicada explicitamente. Hemos estado utilizando la Implernentaci6n de Referencia J2EE para 10s ejernplos de este libro. Corno hernos descrito en 10s capitulos anteriores, el servidor puede ser iniciado ejecutando el archivo j 2ee. bat en el directorio ' :J2EE-HOME% \bin. Podernos desplegar nuestro archivo WAR ejecutando el archivo deployt 001. bat en el rnisrno directorio. Despuks de que la aplicacidn haya sido perfectarnente desplegada y configurada, debe poder acceder a la aplicacidn de chat mediante su navegador Web.

iCuando deben utilizarse 10s archivos WAR?


Aunque el formato de un archivo WAR es el mismo que el un archivo JAR, 10s archivos WAR difieren significativamente de 10s archivos JAR. El proposito de un archivo JAR es empaquetar clases y sus recursos relativos en un fichero en archivo comprimido; un archivo WAR representa una aplicacidn Web, no s610 un archivo de clases. Por lo tanto, k u i n d o debemos utilizar archivos WAR? Los archivos WAR no son apropiados durante las etapas de desarrollo, cuando 10s servlets de la aplicacibn Web pueden recompilados con frecuencia. Se invertiria mucho tiempo en volver a crear un archivo WAR cada vez que un sewlet fuera recompilado. Muchos contenedores Web proporcionan funciones de auto-recarga para archivos de clase sewlet compilados y archivos JSP. Esta funcion resulta muy l i d cuando 10s componentes de una aplicacion son alterados con frecuencia. C o n una funcibn de auto-recarga, el contenedor no necesita ser reiniciado cuando se realiza un cambio en un sewlet o en una pigina JSP. En su lugar, el contenedor recargari automiticamente laclase modificada. paraactivar la El sewidor J2EE especifica el atributo r e l o a d a b l e = " t r u e " en u n a e t i q u e t a < ~ o n t e x t > auto-recarga:

Cuando e s t a e t i q u e t a < c o n t e x t > es ariadido a s e r v e r .xml bajo % J2EE-HOME\conf \, el sewidor recarga automiticamente 10s archivos de clase Java y 10s archivos JAR contenidos en WEBI N F \ c l a s s e s yWEB- I N F \ l i b (si es aplicable). Laauto-recarga requiere que el contenedor controle periodicamente 10s directorios de despliegue (10s directorios d o c B a s e en el caso de Tomcat), lo que provocari degradation del rendimiento. Debido a1 sobregasto extra, la recarga automitica no es de uso recomendado en aplicaciones Web en el nivel de production. Los archivos WAR son mis apropiados hacia el final de la fase de desarrollo de aplicaciones, cuando el nlimero de cambios de cddigo disminuye y comienza la planificacion de la produccibn final de la aplicacion. C o n 10s archivos WAR, podemos empaquetar aplicaciones Web utilizando una estructura lbgica y, cuando el archivo WAR sea desplegado, el contenedor tendri acceso a recursos dentro de la aplicacibn Web. En la siguiente seccibn, trataremos el tema de cbmo el contenedor puede localizar 10s recursos que son solicitados, bien por un cliente o por otro recurso dentro de la aplicacibn Web.

Asociar de solicitudes a aplicaciones y servlets


En un contenedor Web, cada aplicaci6n Web esti asociada a un contexto y todos 10s recursos de una aplicacion Web existen con relacion a ese contexto. Por ejemplo, en la aplicaci6n de bienvenida del capitulo 5, el archivo i n d e x . h t m l existe en el contexto / g r e e t i n g / . Puede acceder a i n d e x . h t m l en http:// locaIhost:8080/greetinglindex. html. Cada contexto tiene tambikn un objeto s e r v l e t c o n t e x t asociado. Parala aplicacibn Web, este objeto S e r v l e t c o n t e x t representa una vista del contenedor Web y permite a 10s sewlets acceder a recursos disponibles para ellos. s e r v l e t c o n t e x t es el cajbn de arena en el que sewlets y otros componentes Web comparten toda la information.

Despliegue Web, autentificacion y empaquetado


En capitulos anteriores, hernos accedido a servlets rnediante nornbres especificados para cada servlet en el descriptor de despliegue. En esta seccibn, analizarernos c6rno las solicitudes son asociadas a servlets de un rnodo rnis generic0 y flexible. Una solicitud H'ITP siernpre contiene un identificador uniforrne de recursos, Uniform Resource Identifier (URI) que identifica el recurso solicitado. Los tkrrninos Uniform Resource Locator (URL) y Uniform Resource Identifier (URI) son utilizados a rnenudo de forrna incoherente en libros, especificaciones y otros docurnentos. Esto se debe en parte a que URL es uno de 10s subgrupos de URI rnis cornGnrnente utilizado para protocolos especificos de red. Utilizarernos 10s terrninos tal y corno son utilizados en la especificacidn de API Servlet, que es pricticarnente igual a su uso en la especificaci6n H'ITP:
O

U n URI es un string utilizado para identificar un recurso de Internet, en un espacio de nornbre. De hecho, la direccidn de un recurso de Internet puede ser codificada en forma de URI. U n URL es un string, en jun forrnato para un protocolo es~ecifico corno h t t p , f t p , t e l n e t , news, etc. Este forrnato incluye un esquema (por ejernplo, h t t p ) , el nornbre del dorninio del servidor, una ruta y posiblernente parirnetros string de consulta. otras palabras, la parte que denota la ruta.

en o Una ruta URL es la parte del URL que identifica el recurso dentro de un servidor es~ecifico; Por ejernplo, el URI http://www.wrox.com/Consurner es un URL para el esquerna h t t p , localizado en el servidorwww.wrox. comy la ruta URL de este recurso es / c o n s u m e r . De la descripcidn anterior, podernos deducir que 10s URL y URIs son muy sirnilares. Sin embargo, la principal diferencia estriba en que un URIpuede o no describir un recurso fisico, rnientras que un URL debe describir un recurso fisico. Por ejernplo, considere la declaraci6n DOCTYPE del descriptor de despliegue de la aplicaci6n Web. La declaraci6n DOCTYPE especifica un D T D para el descriptor de despliegue que el contenedor Web utiliza para validar el descriptor de despliegue. Lo que esta declaraci6n contiene es un URI, por ejernplo: http:1,' java.sun.coWj2ee(dtdsANeb-app-2-3.dtd. El URI especificado en esta declaracidn puede existir o no fisicarnente. Aunque en el caso de este ejernplo particular encontrari de hecho un D T D en esta position, esto no siernpre es necesariarnente cierto. El analizador XML que analiza el descriptor de despliegue puede en su lugar asociar este URI a un D T D disponible en el sisterna local de archivos (utilizando un solventador de entidades). Los contenedores Web utilizan el rnisrno concept0 para identificar aplicaciones Web y 10s recursos que en ellas se encuentran. C o n la ayuda de la ruta URL, 10s contenedores Web pueden identificar la aplicaci6n, el contexto de servlet asociado y el recurso dentro de la aplicaci6n. Para que esto sea posible, cada aplicaci6n Web debe ser asociada a un Gnico prefijo de ruta de URL, por ejernplo / c h a t . Este prefijo de ruta especifica un espacio de nombre Gnico para todos 10s recursos con la aplicacion Web. El contenedor Web utiliza este prefijo para asociar solicitudes a recursos dentro de la aplicaci6n Web. Para ver cdrno funciona este rnecanisrno, considere un archivo h e l p . h t m l dentro de un subdirectorio de ayuda de una aplicaci6n, con su raiz desplegada con una ruta de contexto / c a t a l o g en un contenedor Web localizado en http://localhost:8000. A este recurso se puede entonces acceder corno http:) localhost:8000/cataloglhelp/help.html.Es similar a tener el archivo h e l p . h t m l en el subdirectorio / c a t a l o g / h e l p bajo el documento raiz de un servidor Web localizado en http:Nlocalhost8000. En este aspecto, el cornportarniento del contenedor es similar a1 de un servidor Web, except0 en que el contenedor utiliza el nornbre de ruta de contexto para identificar la aplicacion. El nornbre del servidor s i n e corno raiz del docurnento para localizar recursos dentro de la aplicacidn. Por ejernplo, considere dos aplicaciones desplegadas en el misrno servidor: una con la ruta de contexto / t e c h s u p p o r t y la otra con la ruta de contexto / c h a t . Cuando el contenedor Web recibe una solicitud H T T P con una ruta que empieza por / c h a t , el contenedor puede deterrninar que la solicitud debe ser

Capitulo 9
rnanejada por la aplicaci6n Chat y, de un mod0 similar, puede deterrninar que todas las solicitudes que ernpiezan por /techsupport serln manejadas por la aplicaci6n de Apoyo Tecnico. Este rnecanisrno puede extenderse a servlets dentro de aplicaciones. Del rnismo mod0 en que la ruta de context0 se utiliza para asociar una solicitud a una aplicaci6n Web, las asociaciones de ruta de URL puede utilizarse para representar solicitudes para servlets. Hay dos pasos en este proceso de asociaci6n: Definir nombres de alias para servlets: Recuerde que, en la aplicaci6n Chat, hemos definido tres clases de servlets en el descriptor de despliegue con nombres de alias:

ksta es simplemente una asociaci6n de nombres cortos de alias a nombres de clase de servlets. Los nombres de alias le permiten referirse a servlets mls ficilmente y reemplazar la clase de irnplementaci6n por un servlet sin tener que modificar las referencias a1 servlet dentro de la aplicaci6n. Este nornbrado es un parte del proceso de definir un servlet en el descriptor de despliegue.
CI Asociar rutas de URL a nombres de alias de servlets

En ejemplos previos, hemos accedido a servlets a travts de rutas corno /context-name/ servlet /servlet-name. Por ejemplo, se accede aChatAdminServlet corno http:// localhost8000/chat/servlet/chatAdmin.Asociando en su lugar solicitudes de ruta de URL a servlets, podremos proporcionar a nuestros servlets nombres mis 16gicos. Estudiernos el segundo paso (asociar rutas de URL a nombres de alias de servlets) con mis detalle. Considere las siguientes reglas para asociaci6n de rutas de URL para servlets: RutaURL
/admin /list /chat

Alias de servlet
chatAdmin 1istRooms chatRooms

URL
http://localhost:8000/chat/admin http://localhost:800O/chat/list http://localhost:8000/chaVchat

Las dos primeras columnas de tabla enumeran 10s nombres de ruta de URL que pretendernos utilizar para cada servlet, rnientras que la tercera columna rnuestra 10s verdaderos URL que podernos utilizar para acceder a estos servlets. Para facilitar esta asociacibn, podemos utilizar las etiquetas <servlet-mapping> de la aplicaci6n Web. Por ejemplo, podriamos cambiar el descriptor de despliegue de nuestra aplicacion de chat corno se rnuestra a continuaci6n:

Despliegue Web, autentificacion v empaquetado

<! DOCTYPE

Web-app P U B L I C "-//Sur, M l c r o s y s t e m s , I n c . / / D T D W e b A p p l l c a t l o n " h t t p : / / j a v a . sur,.corn/ jZee/dtds/Web-app-2-3.dtd1'>

2. EN EN"

Este descriptor de despliegue modificado especifica que:


O Las solicitudes que empiecen por /admin/* serhn encaminadas hacia el servlet chatAdmin. Por ejemplo, cuando introduzcamos http://localhost:800O/chat/admin/, entraremos en la pigina de administraci6n de la aplicaci6n de chat. O Las solicitudes que empiecen por /chat / * serin encaminadas a1 servlet chat Rooms e rvl et. O Las solicitudes que empiecen por /list / * serin encaminadas a1 servlet 1is t Roomsservlet.

Capitulo 9
O

Las solicitudes que n o coincidan con estas reglas serin controladas por el contenedor de la forma habitual.

L I ,STROOM-PATH y TambiCn debemos destacar el cambio en 10s valores ~ ~ A D M I N - P A T H CHATROOM-PATH. En capitulos anteriores, estos valores apuntaban a rutas que empezaban por /sewlet per0 ahora podemos utilizar asociaciones de senlet.

Entonces, icuil es la ventaja de utilizar asociaciones de senlet en lugar de utilizar rutas que apunten a senlets? Cuando utilizamos una asociaci6n, varias piginas Web (estiticas, o dinimicas) de una aplicaci6n Web estin vinculadas a la asociacion en vez de a un servlet. Como resultado, las piginas que estin vinculadas a un servlet estin dCbilmente acopladas a1 senlet. Puede cambiar la asociaci6n para que apunte a una versi6n reforzada de un senlet o de un JSP per0 las piginas que estin vinculadas a la asociaci6n estin aisladas de esos cambios. Las asociaciones de ruta son relativas a1 prefijo de ruta del URL del contexto. El contenedor elimina el prefijo de ruta de URI del contexto antes de evaluar las reglas de asociacidn del patr6n URL. Esto significa que una solicitud para / c h a t / a d m i n es enviada inicialmente a1 contexto de aplicaci6n Chat. El contexto de aplicaci6n Chat elimina el prefijo de ruta de URI y compara lo que queda de la ruta con las reglas de asociaci6n del patr6n URL, donde descubriri que la solicitud debe ser manejada por el senlet c h a t A d m i n . Una solicitud con un URL cuyo comienzo es distinto de / c h a t es pasada a un contexto con un prefijo de ruta URI que coincida y las reglas de asociaci6n especificadas para esa aplicaci6n Web son aplicadas de nuevo para establecer c6mo manejar la solicitud. En todas las asociaciones anteriores, hemos utilizado nombres tales como /chat, /admin y /list para apuntar a 10s tres servlets. Esta asociaci6n tiene una consecuencia: si tiene contenido en directories con nombres similares, el contenedor n o podri senidr dicho contenido directamente. Por ejemplo, si tiene unapigina HTMLen%BOOK-HOME% / C h 9 / c h a t / l i s t / h o w t o . h t m l , la asociaci6n/chat evitari que el contenedor sirva esta pigina. En su lugar, el senlet es invocado cuando un usuario prueba este URL. Debemos elegir nuestras asociaciones con cuidado para asegurarnos que no hay conflictos de este tipo. La siguiente figura resume la asociaci6n de ruta para el senlet chatAdmin:

1.El contenedor
prefijo de ruta URI para encontrar la apl~cacldn Web i s t a se asocla a la ruta real de la apllcaclon s~tuada en

2 El contenedor ut~llzala asoc~ac~on de


del nornbre la sollcltud y la asoc1ac16n del servlet para encontrar la clase del servlet: /adrnln - adrnmservlet

I
)

1
1

El diagrama muestra c6mo las diferentes partes de un URL se asocian a:


0

U n senidor, con un contenedor Web Una aplicaci6n Web y por lo tanto a un contexto

o U n senlet para procesar la solicitud


El senidor utiliza una asociaci6n de prefijo de ruta URI para localizar la correcta aplicaci6n Web. El contexto de la aplicaci6n Chat utiliza la parte restante de la ruta URI para encontrar el nombre del senlet para procesar la solicitud y finalmente una asociaci6n nombre-a-clase para localizar la clase del servidor.

Despliegue Web, autentificacion y empaquetado


Podemos construir un U R L para acceder a una aplicacidn Web desde un cliente utilizando el siguiente patr6n generalizado:

Es sencillo trasladar una aplicacidn a un sitio diferente en el espacio del nombre de un contenedor Web ya que todas las rutas U R I dentro de un contexto son relativas a la ruta U R I raiz del contexto. Por ello, si introducimos una nueva versidn de la aplicacidn Chat y queremos utilizar el prefijo / c h a t para la nueva versidn mientras que seguimos proporcionando acceso a la vieja versidn en / o l d c h a t , solo tenemos que cambiar las asociaciones de contexto del contendor Web. En este caso, asociaremos / c h a t a la nueva versidn y l o l d c h a t a la vieja versidn.

El acceso controlado a aplicaciones Web para salvaguardar datos y recursos de valor es un requisito muy cornun. El enfoque m i s comunmente utilizado para la seguridad de aplicaciones Web es utilizar formularios de registro y autentificar usuarios basindonos en nombres de registro y contrasefias. Este enfoque se combina normalmente con Secure Sockets Layer (SSL) con certificados digitales de lado servidor obtenidos de vendedores de certificados como Verisign (http://www.verisign.corr\/). SSL es un protocolo de seguridad y especifica un proceso para que servidores Web y navegadores establezcan un canal de comunicacidn seguro sobre HTTP. Este protocolo incluye etapas en las que navegadores y servidores intercambian ciertas claves privadas antes de intercambiar datos de aplicacidn. Navegadores y servidores utilizan estas claves privadas para cifrar y descifrar datos de aplicacidn sobre HTTP. C o m o este protocolo permite el intercambio de informaci6n de forma cifrada, es m i s seguro que enviar informaci6n sin cifrar. Aunque son posibles implementaciones mis seguras (en ocasiones son necesarias), nos centraremos en c6mo pueden ser configurados 10s contenedores Web y las aplicaciones Web para implementar la autentificacibn de usuario. Fijese en que la mayoria de 10s servidores Web ofrecen mecanismos para crear dominios y listas de control de acceso para controlar el acceso a diferentes recursos Web. En esta seccidn, n o estamos interesados en funciones de este tipo; en cambio, nos centraremos en las funciones posibles con la especificaci6n de servlet. Antes de analizar 10s detalles sobre c6mo configurar 10s contenedores Web para proporcionar un acceso seguro, es Gtil comprender el enfoque traditional que no confiaba en el contenedor. Este era normalmente implementado del siguiente modo: 0 Programacidn de la aplicacidn para tener uno o mis puntos de entrada con formularios de registro. Por ejemplo, en la aplicacion de chat, podemos proporcionar una pigina de registro, con un formulario para aceptar el nombre de registro y la contrasefia del administrador del chat.
0 Autentificacion del usuario cuando envia el formulario de registro, preferiblemente sobre H?TPS. Con

este prop6sit0, debe verificar a1 usuario en una base de datos de usuario creada previamente o un archivo que contenga nombres de registro de usuario y contrasefias. Por ejemplo, en el caso del servlet de administracidn del chat, podriamos mantener a todos 10s usuarios con capacidades administrativas en una base de datos. Seria necesario un nuevo servlet, llamado L o g i n s e m l e t , para recibir esta solicitud, conectar a la base de datos y comprobar si el nombre de usuario y la contrasefia coinciden. 0 Una vez se ha registrado con kxito, el usuario sera reenviado a1 servlet de administraci6n {Quk salvaguardas pueden introducirse para evitar que el usuario acceda directamente a1 servlet de administracidn? Hay dos posibilidades:

Capitulo 9
0 El servlet de adrninistraci6n debe ser capaz de saber si el usuario ya se ha registrado. Podemos utilizar un atributo de sesi6n, u s e r n a m e , que es establecido por el servlet de registro cuando se ha realizado el registro. El servlet de administracion puede verificar si este atributo existe en la sesi6n y si no, puede enviar algun contenido que explique que el usuario no puede utilizar el servlet de administracibn. 0 Alternativarnente, el servlet de administraci6n puede redirigir al usuario a un servlet de registro y despuks de completar el registro, instruye a1 servlet de registro para que devuelva a1 usuario a1 servlet de administracion. Considere el siguiente seudo-c6digo para modificar el servlet de administracion:
protected void doFost(HttpServ1etRequest req, HttpServletResponse res) { HttpSession session = req.getSession ( ) ; String userName = sessior~.getAttribute("username"); if (username == null I I username.length0 == 0 ) { session.setAttribute ( " r e r " , "/servlet/adminServlet") ; RequestDispatcher, rd = request.getRequestDispatcher( "/servlet/loginServlet"); rd.forward(request, response); 1 else { / / Autentificacibn de usuario. Proceder con administracidn

El fragmento de c6digo intenta recuperar el u s e rname de la sesi6n actual de usuario (observe que la sesi6n existe aunque el usuario no haya sido autentificado). Si el u s e r n a m e no se encuentra en la sesi6n, el servlet establece un nuevo atributo r e f e r r e r en la sesibn, con la ruta de URL del servlet de adrninistraci6n como su valor. El servlet de administraci6n dirige entonces a 10s usuarios a1 servlet de registro v i a ~ e q u e s t ~ i s p a t c h e r . Consideremos ahora el l o g i n s e r v l e t :
protected void doPost(HttpServ1etRequest req, HttpServletResponse res) I HttpSession session = req.getSession0; String userName = req.getSession ( ) .getAttribute ( "username") ; ifiusername == null) { / / Obtener 10s parimetros de nombre de usuario y contrasetia de la solicitud.

/ / Acceder a la base de datos y verificar registro y contrasetia / / Si es correto if( ... ) I ref errer = session.getAttribute ("referrer"); RequestDispatcher rd = request.getRequestDispatcher(referrer1; rd.forward(request, response); 1 else { / / Enviar contenido que denote fallo en el registro.

Este servlet cornprueba si el usuario es vilido; si es asi, redirige a1 usuario de vuelta a1 referente. En nuestro caso, este es el senlet de administraci6n. Los fragmentos anteriores de c6digo ofrecen un posible enfoque generic0 para irnplementar la autentificacih. Observe que debe incluir el primer fragmento de c6digo (mostrado para ChatAdminS e r v l e t ) en todos 10s servidores que requieran acceso autentificado.

Despliegue Web, autentificacion y empaquetado


Este enfoque se conoce como seguridad prograrnada. Es decir, el desarrollador implementa la seguridad programando. Si desea implementar seguridad para un servlet o una pigina JSP, tendri que modificar explicitamente el servlet o pigina JSP para verificar si la sesi6n pertenece a un usuario autentificado y, si no, dirigir a1 usuario a1 loginservlet. Este enfoque resulta a menudo satisfactorio para aplicaciones pequeiias para las que 10s requisitos de seguridad y usuarios cambian rara vez. Existe otro enfoque, llamado seguridad declarativa. En este enfoque, no se programa la seguridad; en su lugar, declara que determinados recursos requieren acceso autentificado y que el usuario debe tener una funci6n especifica.

La seguridad declarativa permite a1 contenedor Web implementar de forma efectiva el seudo-c6digo que escribimos para el servlet de administraci6n e implementar por completo el servlet de registro. Si el contenedor detecta que no hay un usuario autentificado asociado a la sesi6n, puede dirigir a1 usuario a una pigina de registro y verificar el nombre de registro y contraseiia. Si el usuario y la contraseiia son vilidos, el usuario es redirigido a1 servlet de administraci6n. S610 necesitamos instruir a1 contenedor para el que 10s servlets requieren acceso autentificado, realizando las adiciones apropiadas a1 descriptor de despliegue.
En J2EE, el mecanismo de autentificaci6n esti basado en roles. U n rol designa responsabilidades y privilegios del usuario. Por ejemplo, si dos usuarios Jack y Jill son designados como administradores para la aplicaci6n Chat, podemos asignar un rol determinado, chatAdministrator, tanto a Jack como a Jill. Aunque Jack y J i l l son dos usuarios diferentes, ambos pueden desempeiiar el mismo rol en la aplicaci6n. De un mod0 similar, un 6nico usuario puede desempehar m6ltiples roles en una determinada aplicaci6n Web. La especificaci6n API del servlet especifica cuatro posibles tipos de autentificaci6n:
0 Autentificaci6n bisica H T T P 0 Autentificaci6n resumida H T T P 0 Autentificaci6n de cliente HTTPS 0 Autentificaci6n basada en formulario

De h a s , 10s servidores Web tradicionales como Apache implementan el enfoque bisico y el resumido. Examinemos estos tipos de autentificach con mis detenimiento:
0

La autentificacih bisica esti basada simplemente en un nombre de usuario y una contraseiia. Cuando una pigina Web o un recurso es designado con autentificacibn bisica, el servidor Web solicita a1 navegador que le envie un nombre de usuario y una contraseiia. Basindose en esto, el navegador muestra un cuadro de diilogo para capturar el nombre de usuario y la contraseiia, y envia estos valores a1 servidor Web. Este enfoque tambikn puede combinarse con SSL. La autentificacih resumida es similar a la autentificach bisica, except0 en que las contraseiias son transmitidas de forma refundida. En este enfoque, el navegador envia una versi6n refundida de la contraseiia (y un string aleatorio enviado por el servidor, llamado nonce) introducida por el usuario. Los algoritmos de refundici6n, como MD5, generan refundici6n sin retorno (un c6digo) para un determinado texto. El servidor realiza la misma operaci6n en la contraseiia almacenada y comprueba si 10s valores refundidos son 10s mismos. Puesto que las contraseiias refundidas son intercambiadas (en lugar de contrasefias de texto normal), este enfoque es considerado rnis seguro que la autentificaci6n bisica sobre HTTP. Sin embargo, este mecanismo n o es tan utilizado como la autentificaci6n bisica o la autentificaci6n de cliente HTTPS. Para rnis informaci6n sobre este enfoque, vCase RFC-2069 (http://www.ietf.org/rfc/rfc2069.txt).

La autentificacih d e cliente HTTPS requiere el uso de certificados de claves p6blicas y HTTPS


(HTTP sobre SSL). Este es un enfoque rnis seguro ya que requiere un certificado digital que puede utilizarse para verificar si el usuario es q u i h dice ser.

Capitulo 9
La autentificaci6n basada en formulario es la ultima forma de autentificaci6n e ~ ~ e c i f i c a d a pla or
especificacih del servlet. Utilizando este enfoque tambikn puede definir piginas personalizadas de registro y error para la autentificacion. Examinemos ahora las funciones proporcionadas por la especificaci6n de Servlet para seguridad programada y declarativa. Nos limitaremos a1 API para acceder a las credenciales de usuario con registro en forma de usuario y veremos como puede implementarse la autentificacion basada en formulario.

Seguridad programada
La interfaz HttpServletReques t proporciona 10s siguientes mktodos para recuperar informaci6n de rol/usuario de la solicitud:

El &todo getAuthtype0
public String getAuthType ( )

Este mktodo devuelve el tipo de autentificacion utilizado para proteger el servlet. Los posibles valores de retorno son BASIC para indicar autentificacion bisica, s s L para indicar autentificacih basada en SSL, o null en cualquier otro caso.

El &todo getRemoteUser0
public String getRemoteUser0

Devuelve el registro del usuario que realiza esta solicitud; el valor de retorno depende de la implernentacion del contenedor. El mbtodo getUserPrincipal0
public java.security.Principa1 getuserprincipal0

Devuelve el objeto Principal asociado a la sesi6n de usuario actual. U n objeto Principal es utilizado para representar una identidad, como el registro o incluso un certificado digital, perteneciente al usuario solicitante.

El h t o d o isUserRoleO
public boolean isUserInRole(String role)

Devuelve true si el usuario actual tiene el rol especificado en el argumento. Es conveniente destacar que estos mktodos pueden o no haber sido implementados en su contenedor Web. Su propbsito es permitir una implementaci6n mis sofisticada de la autentificacion. Estos mktodos sencillamente otorgan acceso a informaci6n que puede haber sido reunida por la implementaci6n subyacente del contenedor Web.

Autentificacion basada en un formulario


El enfoque de la autentificacion basada en un formulario esti basado en el contenedor Web que invoca automiticamente a una plgina de registro, basindose en las restricciones de seguridad establecidas en una pigina o recurso de la apkacibn Web. Consideremos la implementaci6n de una funci6n de registro basado en formulario para la aplicaci6n de chat.

Despliegue Web, autentificacion y empaquetado


Primero, definiremos un rol llamado c h a t A d m i n i s t r a t o r con capacidades tales como "afiadir a", "eliminar den y "modificar la lista de salas de chat". Puesto que todas estas actividades pueden ser realizadas por C h a t A d m i n S e r v l e t , es necesario un rol llamado c h a t A d m i n i s t r a t o r para invocar este servlet. Designemos a Joe como el usuario que tiene el rol de c h a t A d m i n i s t r a t o r . Joe tambiCn puede tener otros roles tales como s y s A d m i n i s t r a t o r . El objetivo es permitir el acceso 6nicamente a aquellos usuarios que tengan un rol llamado c h a t A d m i n i s t r a t o r para invocar el servlet de administraci6n del chat. Comenzamos con el descriptor de despliegue y afiadiremos el siguiente a1 archivo Web. xml de nuestra aplicaci6n Chat:
<Web-app> < ! - Ir~sert servlet and cor~text defir~itions ->

<login-conf ig> <auth-method>FORM</auth-method> <realm-name> Form-Based Authentication for Chat Administration. </realm-name> <form-login-config> < f o r m - l o g i n - p a g e > / l o g i r ~ .html</form-10gir1-page> <form-error-page>/error.html</form-error-page> </form-login-conf ig> </login-conf ig> </Web-app>

Este descriptor de despliegue especifica la restricci6n de seguridad y el esquema de autentificaci6n. Mls especificamente, la e t i q u e t a < s e c u r i t y - c o n s t r a i n t > incluye definici6n de unacolecci6n de recursos y el requisito de autorizaci6n. La colecci6n de recursos en el anterior descriptor incluye todas las solicitudes GETconelpatr6n U R L / a d m i n / * . L a e t i q u e t a < u s e r - d a t a - c o n s t r a i n t > especificac6mo debenser transmitidos 10s datos por la conexi6n. Los valores posibles son NONE, INTEGRAL y CONFIDENTIAL. El valor NONE utilizado aqui significa que no hay requisito de transporte; un valor de INTEGRAL indicaria que la transmisi6n de datos subyacentes debe garantizar la integridad de datos y un valor de CONFIDENTIAL requeriria que la transmisidn subyacente deberia evitar que otras entidades observaran 10s datos. El apoyo a estos valores depende tanto de clientes como de servidores. Por ejemplo, 10s navegadores cliente habilitados por SSL y contenedores Web pueden participar en transmisih CONFIDENTIAL. El e l e m e n t o < s e c u r i t y - c o n s t r a i n t > tambiCnincluyeunaetiqueta<auth-constraint> para la colecci6n de recursos. En el ejemplo anterior, este elemento incluye el elemento < r o l e - n a m e > con valor c h a t A d m i n i s t r a t o r . Por lo tanto, s61o usuarios con rol c h a t A d m i n i n s t r a t o r tiene permitido el acceso a 10s recursos.

El siguiente paso es definir una configuration de registro. La e t i q u e t a < l o g i n - c o n f i g > especifica c6rno debe ser ejecutada la autentificaci6n. En nuestro ejernplo, estarnos utilizando autentificaci6n basada en un una pigina de registro y una pigina de error. Siernpre que el forrnulario, que requiere que e~pecifi~uernos registro es requerido, el contenedor Web envia autorniticarnente la pigina de registro. Siernpre que falla el registro, el contenedor Web envia autorniticarnente la pigina de error. En nuestro ejernplo, estarnos utilizando piginas l o g i n . h t m l y e r r o r . h t m l respectivarnente para conseguir esto. ~ s t es a la pigina l o g i n . h t m l :

<body> <hl>Please Login</hl> <form action="j security check" method="POST"> <table border="On width="30%" cellspacing="3" cellpadding="2"> <t r> <td><b>Log1r,</b></td> <td><input type="textn size="2OW name="j username"></td> </tr> <tr> <td><b>Password</b></td> <td><input type="passwordW size="lOW name="j passwordW></td> </tr> <t r> <td><p><input type="submit" value="Sign inM></td> < / t r> </table> </form> </body> </html>

La especificaci6n de senlet requiere que el parirnetro de accidn del forrnulario sea j - s e c u r i t y-check, el nornbre de entrada de registro sea j - u s e r n a m e y el nornbre de entrada de la contrasefia sea j - p a s s w o r d . El nornbre j - s e c u r i t y - c h e c k es un recurso dentro del co?tenedor que irnplernenta la autentificaci6n. N o hay lirnitaciones de este tipo en la pagina e r r o r h t m l . Este es un ejernplo de archivo e r r o r .h t m l deprueba:

<html> <head> <title>Login Authentication</title> </head> <body bgcolor=" #eOdOcO"> <hl>Login now to create chat rooms</hl> <h3>Sorry, incorrect username/password. T r y again</h3> <form action="j security check" method="post"> <table border=" 0" wldth="30%" cellspacing="3" cellpadding="Z"> <t r> <td><b>Logiri</b></td> <td><ir~put type="textq' size="20" name="j username"></td>

Despliegue Web, autentificacion y empaquetado

Esta pigina incluye de nuevo el formulario de registro con un mensaje que solicita otro intento aunque podria tener cualquier otro tip0 de contenido. El siguiente paso es aiiadir nuestro usuario Joe. El procedimiento exacto depende de la implementaci6n de 10s campos de seguridad proporcionados por el contenedor. C o n la Implementaci6n de Referencia JZEE, que se ejecuta con Tomcat, nuevos usuarios y roles pueden ser aiiadidos en el archivo %J2EE-HOME%\conf\tomcat-users.xm1:

...
<user name=" joe" password=" joe" roles="chatAdmin" </tomcat-users>

/>

DespuCs de aiiadir el nuevo usuario y rol, cuando introducimos http://localhost:800O/chat~admin en nuestro navegador, debemos ver la pigina login.html en donde podemos introducir el registro y la contraseiia deseada. En servidor verifica estos valores e invoca el servlet de administraci6n. Observe que una vez que nos hemos registrado, el registro s610 es vilido para la presenta sesi6n. Del mismo modo, si introducimos un nombre de usuario o contraseiia incorrecta, el contenedor enviari la pigina error.html. Este mecanismo de autentificaci6n es muy sencillo de implementar y no requiere cambios en su c6digo de fuente existente. Simplemente tiene que decidir que rol requiere cada recurso y especificarlo en el descriptor de despliegue. Sin embargo, este enfoque tiene una limitaci6n. En la actualidad, la especificaci6n de Servlet no incluye apoyo para la verificaci6n de registro y contraseiia personalizados. Depende del implementador del contenedor decidir c6mo y d6nde almacenar 10s datos de registro y contraseiia, y verificarlos. Los servidores de aplicaci6n JZEE como Tomcat, Orion y WebLogic proporcionan API que pueden ser utilizados para implementar autentificaci6n personalizada. El contenedor invoca estos API durante la fase de autentificacibn. Lo unico que tiene que hacer el desarrollador es implementar ciertas interfaces especificadas en 10s API de propiedad. Estos API tambiCn pueden utilizarse para construir interfaces que creen y gestiones usuarios y roles de usuario. Debe comprobar la documentaci6n de su servidor antes de planificar cualquier solucion de seguridad. En nuestro sencillo ejemplo de chat, desplegado con la Implementacidn de Referencia, 10s nombre de registro y las contraseiias se almacenarin utilizando texto llano en el archivo % J2EE-HOME% \conf\tomcat-users . xml. Esteenfoque tienedoshitaciones:
0 Las contrasehas son almacenadas en texto llano que, como formato, no es aceptable para ninguna

aplicaci6n online segura.


0

Hay muy poco o ningun apoyo de infraestructura para gestionar las cuentas de usuario. Los cambios requieren modificar el archivo XML.

La actual especificaci6n de Servlet no resuelve estas limitaciones. Para implementar una seguridad efectiva, necesitaremos API especificos del vendedor.

Configuracion de despliegue
Puede personalizar muchas configuraciones importantes de la aplicaci6n Web mediante del descriptor de despliegue. Estas configuraciones incluyen:

457

Capitulo 9
0

Parimetros de inicializacibn de contexto. Especificar y acceder a 10s parimetros de iniciahacidn de contexto Panimetros de inicializacibn de servlet. Especificar y acceder a parimetros de inicializaci6n de servlet

U Carga de senlet. Especificar las propiedades de inicio de servlets el orden en que deben ser cargadas
0 0

Configuraci6n de sesi6n. Especificar el interval0 de tiempo limite de sesi6n Asociaciones MIME. Especificar t i p o s ~ para 1 ~ documentos ~ de la aplicacih Web Piginas de bienvenida. La pigina que invoca el contenedor cuando la solicitud URL se asocia a la raiz de la aplicacidn Piginas de error. Pueden ser utilizadas para enviar documentos con sentido para errores HTTP estindar y excepciones personalizadas

Aplicaciones distribuibles. Finalmente, examinaremos brevemente las aplicaciones distribuibles y c6mo podemos habilitar la distribuci6n

La especificacion Java Servlet version 2.3 especifica el descriptor de despliegue en un D T D con la declaraci6n~0~~~~~:
< ! DOCTI PE PUBLIC

Web-app "-//Sun

Mlcrosystems,

Inc.//DTD Web P . p p l l c a t i o n ? . 3 / / E N Q '

"http://]ava.sun.com/j2ee/dtds/Web-app-2-3.dtd1'>

Todos 10s descriptores de despliegue de la aplicaci6n deben incluir esta declaraci6n DOCTYPE.

Parametros de inicializacion de contexto


Los parimetros de contexto son atributos que forman parte de un servlet de contexto. Todos 10s servlets y piginas JSP dentro de una aplicaci6n Web pueden obtener y establecer estos atributos. Los mktodos g e t I n i t P a r a m e t e r ( ) y g e t I n i t P a r a m e t e r N a m e s ( ) puedenserutilizadospararecuperarlos parlmetros de inicializacibn de contexto. En 10s ejemplos del capitulo 8, hemos utilizado estos parimetros de inicializaci6n de contexto para especificar las configuraciones del driver de base de datos y de protocolo, y las rutas URL de varios servlets. Puede establecer 10s parimetros de inicializacih de contexto utilizando 10s elementos < c o n t e x t p a r am> del descriptor de despliegue. El siguiente descriptor de despliegue aiiade un atributo llamadoname:

<context-param>
<param-name>name</param-name> <param-value>Jack</param-value>

</Webapp> El elemento <param-name> hace referencia a1 nombre del parimetro de contexto; kste es el nombre utilizado para recuperar el parimetro d e l 2 e r y l e t c -o n t e -x t utilizando el mktodoget I n i t p a r a m e t e r )r . g e t ~ n i t ~ a r a m e t (e El elemento < p a r a m - v a l u e > corresponde aKaTor String dewelto
()

...

<descripticsri>Name o f </context-param;

Jack.

Jack

is

Jill's

brother. </description>

Opcionalmente, un elemento < d e s c r i p t i o n > puede ser afiadido para cada parimetro de contexto, para hacer que el descriptor de despliegue sea mis descriptivo. Los parimetros de inicializacidn de contexto son aplicables a todos 10s servlets que comparten el mismo contexto.

Despliegue Web, autentificacion y empaquetado

Parametros de inicializacion de servlet


Del mismo mod0 que 10s parimetros pueden ser configurados para el contexto, 10s parimetros de inicializacidn pueden ser especificados para cada servlet. Esto se consigue utilizando el elemento <init param>. El siguiente fragment0 de descriptor de despliegue establece dos parimetros de inicializacibn:

...
<servleti <servlet-name>Jack~/servlet-r~ame).

<servlet-classimypac1:ageee7ack</serv1et-class>
<init-param> <param-name>namec/param-r~ame). <description>Name of </init-param> </sPL\I~E~> </Web-appi

<param-value>Jillc/param-value> J i l l . Jill is J a c k ' s

sister.</description>

U n parametro de inicializacidn llamado name es c o n f i p r a d o para el servlet m y p a c k a g e . Jack. Utilice el mktodo get I n i t p a r a m e t e r ( ) sobre el objeto s e r v l e t c o n f i g para recuperar esteparimetro de inicializacidn. A diferencia de 10s parimetros de inicializacidn de contexto, 10s parametros de inicializacidn de s e n l e t son especificos para cada senlet. Los parimetros de inicializacidn pueden utilizarse para especificar informacidn de inicio para un servlet. Puede que recuerde que nuestro ejemplo de F r e a k S e r v l e t del capitulo 6 tenia un parimetro de inicializacion para especificar un intenalo para la no-disponibilidad del senlet. El F r e a k S e r v l e t utilizaria el siguiente c6digo en su mktodo init ( ) para leer el valor de este parimetro:
public void i n i t ( ) throws ServletException { s t a t e s . a d d ( c r e a t e s t a t e ( " I r ~ i t i a l i z a t i o r ~) ";) String waitIntervalString = g e t S e r v l e t C o n f i g ( ) . g e t I n i t P a r a m e t e r ( " w a i t I n t e r v a l 1 ' ); i f (waitIntervalString != null) { w a i t I n t e r v a 1 = new I n t e g e r ( w a i t I r ~ t e r v a l S t r i n g )i n t v a l u e ( ) ;

I
El mismo proceso de inicializacidn se aplica tambikn a 10s filtros. C o m o hemos en el liltimo capitulo, puede aiiadir elementos <init-param> para cada filtro para especificar 10s parimetros de inicializacidn y sus valores. Remitase a1 descriptor de despliegue para 10s filtros presentado en el capitulo anterior.

Cargar servlets en el arranque


Cargar un s e n l e t conlleva cargar la clase de servlet del archivo de despliegue, instanciar el senlet e inicializar el senlet. Por defecto, el contenedor n o garantiza ninglin orden en el que 10s senlets han de ser cargados. El contenedor puede esperar hasta recibir una solicitud antes de cargar un senlet. Dependiendo del diseiio de su aplicacion, puede que desee especificar que uno o mis servlets sean cargados durante el arranque de la aplicacidn Web. Ademis, puede que estos s e n l e t necesiten ser cargados en un determinado orden. El elemento opcional <load-on-startup> permite especificar este requisito:

Capitulo 9

Cuando el elernento < l o a d - o n - s t a r t u p > esta presente para un servlet, el contenedor lo carga en el arranque del contenedor. Para aplicar un orden en el que 10s sewlets Sean cargados, debe especificar un numero entero positivo para cada sewlet; el contenedor carga 10s sewlets en el orden especificado por estos sewlets. Cuando este elernento no esti especificado, el orden de carga recae en el contenedor. Si especifica el mismo valor para dos o mis servlets, puede que el contenedor utilice cualquier orden para cargar 10s sewlets.

Tiempo limite de sesion


Los objetos H t t p S e s s i o n consumen memoria en el lado sewidor y por ello no deben vivir mucho tiempo despuks de un period0 de inactividad del cliente. Cada cliente, identificado utilizando el objeto H t t p ~ e r v l e t R e q u e s tque , accede a la aplicaci6nWeb tendri un 6nico o b j e t o ~ t t p s e s s i o asociado. n Si una aplicaci6n tiene 10000 usuarios activos, el contenedor tendri 10000 objetos H t t p S e s s i o n , cada uno de 10s cuales puede contener varios atributos. Para limitar el drenaje de recursos que esto provocaria, debe especificarse un tiempo limite de sesi6n. U n tiempo limite puede ser especificado de dos formas:

O Prograrniticamente, invocando el rnktodo s e t ~ a x I n a c t i v ~ e ne rt v a l ( ) sobre el objeto HttpSession

Utilizando el e l e m e n t o < s e s s i o n - t i m e o u t > en el descriptor de despliegue

El siguiente fragment0 extraido de un descriptor de despliegue ilustra el segundo enfoque:


<Web-app> < ! - Servlet definitions >

El intervalo de tiempo limite es especificado en rninutos. El contenedor invalidari autorniticamente la sesion si el tiempo transcurrido entre solicitudes consecutivas procedentes de un cliente es superior a1 ( ) esobre r v a el l objeto intervalo de tiernpo limite especificado. El m ~ t ~ d o ~ e t ~ a x ~ n a c t i v e ~ n t H t t pe ~s s i o n devuelve el intervalo en segundos.

El protocolo HTTP utiliza Multipurpose Internet Mail Extensions (MIME) para describir contenido. Tanto servidores como clientes utilizan tipos MIME para indicar el tip0 de contenido que esti siendo

460

Despliegue Web, autentificacion y empaquetado


intercambiado. U n tipo MIME es un string de forrna t y p e / s u b - t y p e . Ejernplos de algunos de 10s tipos MIME mis comunes i n c h y e n t e x t / h t m l , t e x t / t x t y i m a g e / g i f . Cuando un sewidor Web envia un documento a un cliente, el sewidor debe incluir una secci6n en la respuesta para indicar el tipo del documento. Los navegadores Web utilizan esta informaci6n para representar el documento correctamente. Por ejernplo, si el sewidor Web envia un documento Postscript sin especificar el tip0 de contenido correcto, puede que el navegador no sea capaz de identificar que el cuerpo de la solicitud contiene un documento Postscript y, probablemente, 10s representari de forma incorrecta. La mayoria de navegadores modernos (y, por supuesto, muchos contenedores Web) intentarin identificar el tip0 de contenido basindose en la extension especificada en la solicitud. Sin embargo, sigue siendo una buena prictica especificar 10s tipos MIME para todos 10s tipos de contenido que el sewidor Web pueda enviar. Para el contenido dinimico, el servlet que genera el contenido debe especificar explicitamente el tip0 MIMEutilizando el mktodo s e t C o n t e n t T y p e ( ) sobre el o b j e t o ~ t t p s e r v l e t ~ e s p o n sPero, e. icdmo debemos especificar 10s tipos de contenido de 10s documentos en el Area publica de una aplicaci6n Web? El contenedor Web s i n e tales documentos directarnente a 10s clientes solicitantes. Con el objetivo de que el contenedor puede especificar correctamente 10s tipos MIME para estos documentos, 10s posibles tipos MIME deben ser incluidos en el descriptor de despliegue de la aplicaci6n. Por ejemplo, si nuestra aplicacion Web contiene documentos de Microsoft Word, especificaremos el siguiente tip0 MIME en el descriptor de despliegue: <Web-app> < ! S e r v l e t d e f i n i t i o r ~ s ->

El contenedor utiliza esta inforrnacih para establecer correctarnente el tipo de contenido en la cabecera de respuesta. Utilizando este tipo MIME, 10s navegadores podrin entonces identificar correctarnente cbmo debe ser representado el contenido. Cuando no se puede encontrar un tip0 MIME estindar para un documento, tanto contenedores como navegadores utilizarin un tip0 por defecto. El tipo por defecto es normalmente t e x t / p l a i n .

El archivo de bienvenida por defecto para un sitio Web es normalmente un archivo i n d e x . h t m l o un archivo i n d e x . h t m Lo mismo se aplica a una apkaci6n Web. Cuando introduce la ruta URL que apunta a una aplicacidn Web (por ejemp10,http: //www.m y s e r v e r . c o m / c h a t ) , el contenedor muestra el archivo de bienvenida asociado a la aplicaci6n chat. El contenedor tambikn siwe un archivo de bienvenida cuando un URL de solicitud apunta a un directorio que n o puede ser resuelto a un sewlet. N o esti limitado a utilizar i n d e x . h t m l o i n d e x . h t m c o m o archivos de bienvenida para sus aplicaciones Web. Cualquier recurso publico, como un docurnento HTML o JSP, puede ser especificado como archivo de bienvenida utilizando el elemento<welcome- f i l e - l i s t > en el descriptor de despliegue. Por ejernplo, el siguiente fragment0 especifica una lista de archivos como archivos de bienvenida: <Web-app> < ! S e r v l e t d e f i n i t i o n s ->

Capitulo 9

El contedor Web utiliza el primer archivo disponible como archivo de bienvenida. Considere el ejemplo de estructura de aplicacidn Web que examinamos anteriormente en el capitulo:
rnyWebApp\ i n d e x . html login.js p 4 0 4 N o t F c u n d . html images\ logo.gi f banner.gif literature\ s u m m a r y .js p YXOlAnnualReport . p d f Y2001PresidentAddress.pdf WEB-INF\ Web .xml classes\ ShoppingCart.ciass Satalog.class CheckOut.class 1 ib\ dblibrary. j a r xmlTo2ls. j ar

~ s t es e el efecto de la anterior especificaci6n de archivo de bienvenida en el descriptor de despliegue:

URL
http:l/< HOST:PORT>/myWebApp http:l/< HOST:PORT>/myWebApp/literature http:l/< HOST:PORT>/myWe bApp/images

Resultado

myWebApp/index.html
myWebApp/literature/summary.jsp

Muestra el listado de directorio de myWebApp/images/

En el primer caso, el contenedor sirve el archivo index.html mientras que, en el segundo caso, el contenedor s i n e summary j sp ya que index.html no esti disponible. El directorio images/ no tiene configuracidn de archivo de bienvenida por lo que 6ste simplemente mostraria una lista de 10s contenidos del directorio.

Paginas de error
En el capitulo 6, hemos analizado brevemente las piginas de error. El descriptor de despliegue proporciona a 10s desarrolladores un mecanismo flexible para proveer piginas de error basadas en varias excepciones y mensajes de error HTTP. Antes de entrar en mis detalles de este mecanismo, resulta util estudiar brevemente por qu6 10s errores HTTP estindar son relevantes para la programacidn de servlets. Hay dos modos en 10s que un servlet puede indicar un fallo. En ambos casos, la 16gica real para detectar un error es re~~onsabilidad del servlet. La diferencia radica en el procedimiento para indicar un error a1 contenedor Web.

Despliegue Web, autentificacion y empaquetado

Enviar errores
El primer enfoque consiste en utilizar metodos d e ~ t t p ~ e r v l e t ~ e s p o n s e :
public void sendError(int statuscode) throws IOException public void sendError (int statuscode, String message) throws IOException

Ambos metodos establecerin el cddigo de estado de la respuesta H T T P y enviarin la respuesta. El primer0 de estos metodos acepta un codigo de estado, mientras que el segundo tambien acepta un mensaje definido por el usuario para mayor clarificacidn del error.

No debe escribirse mas informacidn de salida despues de ejecutar el metodo sendError ( ) porque
despues de invocar sendError ( ) , el contenedor Web envia un cddigo de estado HTTP y un mensaje de estado H T T P en las cabeceras de la respuesta. Si esti correctamente configurado, el contenedor Web puede enviar un documento concreto que explique el error. El contenedor puede que tambien registre el error. El cliente puede extraer el cddigo de estado y el mensaje de estado de las cabeceras de respuesta. La siguiente tabla describe 10s cddigos de error mis comunes. Todos estos codigos de error son definidos como constantes en la interfaz HttpServletResponse:

C6digo http
400 401 403 404 500 501 503

C6digo de error
SC-BAD-REQUEST
SC-UNAUTHORIZED

Descripci6n
La solicitud es sinticticamente incorrecta Indica que la solicitud requiere autentificacidn HTTP El servidor entiende la solicitud per0 se niega a ejecutarla El recurso de la solicitud no esti disponible U n error en el servidor HTTP causa el fallo de la solicitud El servidor H l T P n o se ajusta a la funcionalidad necesaria para ejecutar esta solicitud El servidor H T T P esti sobrecargado no puede atender la solicitud

SC-FORBIDDEN
SC-NOT-FOUND
SC-INTERNAL-SERVER-ERROR

SC-NOT-IMPLEMENTED

SC-SERVER-UNAVAILABLE

Lanzar ServletException
El segundo procedimiento para indicar un fallo es lanzar una excepcidn j avax . servlet ServletException o u n a d e sus subclases. Puede disefiar unconjunto declases que amplie S e r v l e t E ~ c e ~ t i olanzarlas n, adecuadamente desde sus servlets.

Considere, por ejemplo, un servlet que ejecute el acceso a la base de datos utilizando el API JDBC. Una excepcidn comGn que el sewlet puede encontrar es java sql .SQLException. Puesto que contenedor no puede manejar de forma elegante excepciones de este tipo, la excepcidn no puede ser relanzada a1 contenedor. Su servlet debe, por lo tanto, lanzar una subclase de javax.servlet .Servlet~xce~tionsiempre~uerecibaunaexcepcidnjava. sql. SQLException. Por ejemplo, considere el siguiente fragment0 de c6digo del servlet:

try { / / Acceso a base de datos falla debido a una falta de conexi6n 1 catch(SQLException e) {

Capitulo 9
t h r o w n e w TryAgainException(e.getMessage(), e ) ;

I
La e x c e p c i 6 n ~y r~ g a i n ~ x c ei po tn puede ser especificada del siguiente modo:
public class TryAgainException extends ServletException { public TryAgainException (String message, Throwable cause) super(message, cause); 1
{

C o n este c6dig0, el contenedor recibiri una e x c e p c i 6 n ~ r y ~ g a i n ~ x c e p tsiempre ion que el senlet encuentre una excepcibn java .s q l . SQLExcept ion. El siguiente paso es comprender c6mo conseguir que el contenedor maneje estas excepciones.

Manejar errores y excepciones HTTP


Utilizando elementos <error-page> en el descriptor de despliegue, puede especificar c6mo debe una aplicaci6n Web manejar errores y excepciones HTTP de period0 de ejecuci6n. Para cada error o excepci6n HTTP, el URL de un recurso puede ser especificado de mod0 que siempre que el contenedor reciba un error o exception HTTP que coincida, h e enviari el recurso especificado a1 cliente. Este extract0 del descriptor de despliegue certifica que el contenedor enviari el archivo /errors / T r y A g a i n html si se recibe la excepci6n T r y A g a i n E x c e p t i o n o aparece el c6digo de error H t t p S e r v l e t R e s p o n s e . S C H t t p S e r v l e t R e s p o n s e . S C _ S E R V E R _ U n a v a i l a b l S E R V E R R U n a v a i 1 a b l e :

<Web-app> < ! - S e r v l e t d e f i n i t i o n s ->

Entonces, k b m o debemos saber si lanzar excepciones o generar c6digos de error? Los c6digos de error H T T P pueden ser utilizados para especificar errores HTTP comunes. Sin embargo, para ello tendri que asociar errores a c6digos de error HTTP apropiados y esto no siempre resulta ficil. Los cbdigos de error H T T P tienen un significado perfectamente definido y 10s c6digos de error inapropiados pueden cambiar el io tn p a r a significado del error. Resulta mis flexible utilizar subclases de j avax .sql .~ e r v l e t ~ x c e p indicar errores de aplicaci6n. El valor de la etiqueta <locat ion> puede apuntar a un senlet, a una pigina JSP o a un archivo estitico. En casos en 10s que la ubicacibn es un senlet o una pigina JSP, el servlet que lanza la excepcibn puede configurar 10s siguientes detalles referidos a1 error utilizando el mktodo setAttribute ( ) en la interfaz
HttpServletRequest:

O C 6 d i g o d e e s t a d o p a r a j a v a x . s e r v l e t .error. status-code O Tipodeexcepci6nparajavax. servlet .error. exception-type O Mensajeparaj avax. servlet .error .message
El senlet o pigina JSP de manejo de errores pueden acceder a estos atributos desde el objeto solicitud.

Despliegue Web, autentificacion v empaquetado


Por ejemplo, supongamos que la ubicaci6n es un servlet ( ~ h o w ~ r r o r ~ e r v l e Este t ) . servlet podria conseguir mis informaci6n sobre error incurrido utilizando el siguiente c6digo en su mktodo d o G e t del siguiente modo:

0,

protected void doGet(HttpServ1etRequest request, HttpServletResponse response) { / / Obtener el c6digo de estado String statuscode = (String) request.getAttribute("javax.servlet.error.stats code" Throwable exeption = (Throwable) request.getAttribute("java~.servlet.error.exceptior~ type" String message = (String) request.getAttribute("javax.serv1et.error.message"
//

Adoptar medidas apropiadas aqui

De este modo, el servlet tiene acceso a aquello que provoc6 la excepcibn. Este enfoque es similar a un bloque de captura de manejo de excepciones, except0 en que tiene lugar sobre la solicitud HTTP. El sewlet anterior que maneja el error tiene acceso no s d o a1 mensaje y cbdigo de error, sin0 tambikn a1 objeto excepci6n lanzado por el servlet que lanza la excepcibn.

Aplicaciones distribuibles
La versi6n 2.2 de la especificaci6n J2EE introduce la noci6n de aplicaciones distribuibles y contenedores distribuibles. El prop6sito de estas caracteristicas es hacer frente a reajustabilidad, disponibilidad y rendimiento. U n contenedor Web distribuible consiste en una serie de Miquina Virtuales Java UVM), ejecutadas en una o mis miquinas host. Antes de analizar con detalle las aplicaciones distribuibles, veamos c6mo son configurados 10s contenedores Web normalmente. El siguiente diagrama muestra una sencilla instalacion (hardware) de un contenedor Web:

Cl~ente Web

Se~ldor Web (con u n plug-ln)

Contenedor Web

La mayoria de 10s contenedores Web proporcionan uri mecanismo tal de conexidn exterior a1 proceso que un contenedor Web pueda ser desplegado detris de un servidor Web existente. Este enfoque tiene varias ventajas. La ventaja fundamental es la capacidad de integrarse a un servidor Web existente. En segundo lugar, el servidor Web puede servir todo el contenido estitico, dejando a1 contenedor Web que procese el contenido dinimico. iC6mo puede el servidor enviar solicitudes el contenedor Web? Los servidores Web especifican normalmente un API plug-in gracias a1 cual las solicitudes HTTP de cierto tip0 pueden ser delegadas en implementaciones de este API. Dependiendo de ciertos atributos de una solicitud HTTP entrante, el

Capitulo 9
senidor Web invoca un plug-in especifico que, a su vez, puede enviar la solicitud a1 contenedor Web. Veamos c6mo ocurre. Por ejemplo, el senidor Web Apache tiene un API para construir m6dulos. U n ri16dulo es un plug-in que puede ser desplegado en un senidor Web Apache y puede procesar solicitudes HTTP. Los senidores Web como iPlanet Web Server y Microsoft IIS tienen API similares. La mayoria de contenedores Web comerciales incluyen implementaciones de plug-in para 10s senidores Web mis utilizados. Dependiendo del semidor Web en uso, puede instalar ficilmente uno de estos plugins. El plug-in instalado tendri la capacidad de invocar al contenedor Web. Para que este mecanismo funciones, necesita especificar qu6 tip0 de solicitudes deben ser delegadas en el plug-in. Ejemplos de esta configuraci6n incluyen la especificaci6n de un prefijo en la ruta, como todas las solicitudes que comiencen por " c h a t " en el caso de nuestro ejemplo, o todas las solicitudes a archivos con extensi6n tipo " j s p " , etc. Siempre que el senidor Web reciba una solicitud H T T P que coincida con estos criterios, invocari el plug-in instalado, que enviari entonces la solicitud a1 contenedor Web. Volvamos ahora al anilisis de 10s contenedores Web y las aplicaciones Web distribuibles. Primero, respondamos una importante pregunta: icuil es el objetivo de la distribuci6n? Consideremos una aplicaci6n Web desplegada en un contenedor Web con una unica instancia de una JVM ejecutada. Habitualmente, la JVM procesari todas las solicitudes HTTP, procesari la 16gica de base de datos (si es implementada via senlets/piginas JSP y no es delegada en EJB) y otra 16gica de empresa. A medida que aumente el numero de usuarios que accede a la aplicaci6n Web, la misma JVM (y, por lo tanto, el mismo senidor que la alberga), tiene que procesar la carga incrementada. Debido a esta carga incrementada, la capacidad del senidor para procesar todas las solicitudes dentro de unos limites de tiempo satisfactorios se veri perturbada. En su conjunto, la capacidad de respuesta del contenedor se deteriorari con el increment0 de carga. Considere ahora una situaci6n en la que hay dos JVM mis albergando la misma aplicaci6n Web con un mecanismo para dirigir cada solicitud a una de las JVM ejecutindose en cada uno de 10s diferentes senidores. C o n un mecanismo de este tipo, el procesamiento podria ser distribuido en multiples JVM y senidores. Esto aumenta la capacidad total de procesamiento del contenedor. El siguiente esquema muestra un clister de este tip0 con tres nodos:
.

Contenedor Web
(Nod0 1)

Cliente Web Sewidor Web (con un plug-in) Contenedor Web


(Nod0 2)

Contenedor Web
(Nod0 3)

Despliegue Web, autentificacion y empaquetado


Normalmente, el plug-in desplegado en el servidor Web actba como un elemento equilibrador de carga. Alternativamente, podria haber otro nodo desplegado entre el servidor Web y el resto de nodos, que actuaria como elemento equilibrador de carga. El equilibrador de carga es el que coordina el manejo de solicitudes en 10s nodos del clbster. Teniendo mis instancias mbltiples para compartir la carga, puede aumentar la capacidad del contenedor para procesar cargas rnis pesadas. En teoria, la distribuci6n es un mttodo sencillo para distribuir la carga en mbltiples ejecutados en diferentes servidores. Sin embargo, en la prictica, configurar la distribuci6n no es tan sencillo como parece y requiere configuraciones avanzadas especificas del vendedor. Ademis de configurar el clbster en una red, que puede resultar la parte rnis dificil para un principiante, uno de 10s pasos de configuracidn consiste en elegir una estrategia de distribuci6n de carga. Esta estrategia es el mttodo por el que el contenedor es instruido para distribuir la carga en nodos de un clbster. Una de las estrategias mis combnmente utilizadas se denomina tanda circular y supone enviar cada solicitud a1 siguiente nodo de un clbster. Los contenedores tambitn ofrecen estrategias rnis avanzadas. Estas estrategias tiene en cuenta la capacidad de procesamiento de cada miquina y sus cargas actuales de procesamiento, prioridades, etc. Remitase a la documentaci6n de su contenedor para detalles rnis especificos. Otra consecuencia derivada de la operaci6n de agrupamiento es la recuperaci6n del fallo. La recuperaci6n del fallo tiene que ver con c6mo conseguir un procesamiento ininterrumpido de solicitudes en lugar de un fallo del servidor. Los mecanismos de distribuci6n de carga tienen normalmente la capacidad de detectar un fallo del servidor (mediante sondeo o alguna otra forma de comunicaci6n) y enviar solicitudes a uno de 10s nodos funcionales de mod0 que las nuevas solicitudes puedan ser procesadas sin fallos. Quizis uno de 10s efectos rnis obvios de la operaci6n de agrupamiento es que, en un clbster, una solicitud de un cliente puede ser procesada por un nodo. Pero esto cuenta con una excepci6n, que veremos enseguida. Una vez se ha configurado un clbster, el proceso de activaci6n de distribuci6n para una aplicaci6n Web es bastante sencillo. Ariada el e l e m e n t o < d i s t r i b u t a b l e >a1 principio del descriptor de despliegue (antes de especificar cualquier parimetros de contexto):

Este elemento indica a1 contenedor que esta aplicaci6n puede ser distribuida en un clbster. Aunque este proceso consistente en especificar que una aplicaci6n es distribuible es sencillo, la distribuci6n de carga y la recuperaci6n del fallo resultan procesos complicados en cuanto a1 mantenimiento por parte de la aplicaci6n Web de la sesi6n y el contexto. Como hemos visto en capitulos anteriores, podemos almacenar informaci6n en objetos de sesi6n y de contexto. Entonces, i q u t ocurre con estos objetos de un cluster cuando ningbn nodo puede procesar una solicitud? Cuando un contenedor Web recibe una solicitud HTTP para una aplicaci6n Web, como hemos visto con anterioridad, el contenedor crea y gestiona una sesi6n para el remitente de la solicitud. Los servlets y las piginas JSP que manejan la solicitud puede almacenar informaci6n (estado) en la sesi6n. Puesto que la sesi6n es en si misma un objeto, es mantenida en la JVM de este nodo. i Q u t sucede cuando la siguiente solicitud procedente del mismo usuario es enviada a un nodo diferente del clbster? Para que el otro nodo procese esta solicitud ininterrumpidamente, debe tener la misma sesi6n disponible. De no ser asi, se perderi toda la informaci6n de sesi6nlestado. Para permitir esto, 10s contenedores Web replican la informaci6n de sesi6n tambitn en otros nodos. Que el contenedor replique o no la informaci6n de sesi6n en todos 10s nodos del servlet depende de la implementaci6n del contenedor. Algunos contenedores designan un nodo secundario para cada nodo y limitan la replicaci6n s610 a1 nodo secundario. Otros pueden replicar el estado en todos 10s nodos del clbster.

Capitulo 9
Para que la informaci6n de sesi6n sea replicable, 10s datos almacenados en la sesi6n deben ser serializables. Cuando intente almacenar objetos n o serializables en la sesi6n de una aplicaci6n Web distribuible, el contenedor puede lanzar una excepci6n I 1 l e g a 1 ~ gument r ~ x c e piton. . La replicaci6n de sesi6n tambiin contribuye a la recuperaci6n del fallo. Considere una situaci6n en la que 10s nodos fallen entre dos solicitudes consecutivas. Puesto que la sesi6n es replicada, el contenedor podria establecer la sesi6n en otro nodo y enviar la solicitud a ese nodo. Esto permite el procesamiento ininterrumpido. Sin embargo, tqu6 ocurre si el servidor falla mientras procesa una solicitud? Este aspect0 es especifico de la implementacibn per0 un contenedor debe poder reenviar la misma solicitud a otro nodo. Existe una excepci6n para la replicaci6n de sesi6n. Algunos contenedores permiten la sujeci6n de sesi6n @inning). Este termino hace referencia a un proceso en el que todas las solicitudes recibidas durante una sesi6n son enviadas a1 mismo nodo (estin "sujetas" a un nodo). En tales casos, puede inhabilitar la replicaci6n de sesi6n. Observe que la sujecibn de sesi6n es una espada de doble filo. Si decide utilizar la sujeci6n de sesidn y desactivar la replicaci6n de sesibn, obtendri mejoras en el rendimiento puesto que no habri sobrecarga de replicacion. Sin embargo, a1 mismo tiempo, un cllister de este tip0 n o puede recuperarse de 10s fallos. Finalmente, t q u i sucede con el contexto de sewlet? La especificaci6n de servlet no requiere que la informaci6n de contexto sea replicada en un cl6ster. Por lo tanto, una aplicaci6n Web en cada nodo mantiene su propio contexto. Por este motivo, debemos analizar con cuidado si varios servlets/piginas JSP escriben informacidn en el contexto. C o m o el contexto no se comparte, existe la posibilidad de que hay anomalias. Debemos considerar la posibilidad de almacenar cualquier informaci6n de contexto compartida en un almacin persistente como una base de datos. El mismo principio se aplica tambiCn a variables estiticas y clases semifallo. Puesto que estas variables son locales respecto de la JVM, aseg6rese de que no albergan informaci6n de Iect~ra/~rabacibn. Para resumir, la operaci6n de agrupamiento es una funci6n muy 6til para habilitar el equilibrio de carga y la recuperaci6n del fallo. Como desarrollador, solo son necesarios dos pasos para hacer uso de esta funci6n: convertir la aplicaci6n en distribuible (mediante el descriptor de despliegue) y asegurarse de que todas las variables de sesi6n son serializables.

Resumen
En este capitulo, hemos estudiado c6mo empaquetar y autentificar con seguridad las aplicaciones Web y como utilizar el descriptor de despliegue para configurar aplicaciones en el period0 de despliegue. Los parimetros de configuraci6n de despliegue mis importantes que hemos estudiado son:
0

La inicializaci6n de contexto

La carga de servlet La configuraci6n de sesi6n Las asociaciones MIME

0 0

0 Las piginas de bienvenida y de error

En la arquitectura JZEE, utilizaremos este mecanismo en todo momento, con sewlets, mensajes, transacciones y beans de empresa. A medida que vayamos analizando estos temas en el resto del libro y comencemos a construir aplicaciones de calidad de producci6n, comprobaremos la capacidad y flexibilidad de este mecanismo.

Despliegue Web, autentificacion y empaquetado


Este capitulo concluye.nuestro recorrido por 10s servlets Java. Antes de pasar a las Piginas JavaServer y otros aspectos de la Plataforma Java 2, Enterprise Edition, es conveniente destacar que J2EE ha cambiado el proceso de programaci6n de lado servidor. Es cierto que todavia seguimos 10s principios bisicos de programaci6n Java para construir nuestras aplicaciones pero, a medida que la tecnologia es cada vez mis sofisticada, 10s contenedores tienden a plantear mis y mis restricciones sobre lo que puede y no puede realizarse exactamente. Si, como desarrolladores de programas, reconocemos este hecho y nos atenemos a estas restricciones tanto en la prictica como en el espiritu, nuestras aplicaciones serin mucho mis s6lidas gracias a nuestro esfuerzo.

Fundamentos y arquitectura

El objetivo de la especificaci6n JavaServer Pages USP) es simplificar la creacion de piginas Web dinimicas proporcionando un sistema de composici6n mis conveniente que 10s servlets. Las piginas JSP combinan anotaci6n estitica, como html y XML, con etiquetas de directiva especiales. Las piginas JSP son similares a documentos de directivas pero cada pigina JSP es traducida a un senlet cada vez que es invocada por primera vez. El sewlet resultante es una combinaci6n de la anotaci6n del archivo JSP y el contenido dinimico integrado especificado por las etiquetas de directiva. En este capitulo, analizaremos 10s siguientes puntos:
0 Los bloques de construcci6n de piginas JSP: directrices, elementos de directivas y las acciones estindar
0 Los objetos implicitos provistos para permitir que las piginas JSP accedan a su entorno y el

concept0 de alcance de objeto


0 Las mejoras introducidas en la nueva especificaci6n JSP 1.2 y sus implicaciones para desarrolladores JSP 0 Una aplicaci6n de ejemplo que ilustra la sintaxis central de JSP y el acceso alas clases ayudantes de Java desde las piginas JSP

C 6 m o utilizar las piginas JSP como parte de las aplicaciones Web de Java perfectamente disefiadas

La especificacion JSP 1 . 2
Desde el lanzamiento de la especificacion JSP 1.2 en Septiembre de 1999 y su ripida acogida por 10s vendedores de s e ~ i d o r e sJSP , ha sido un mktodo s6lido y de uso muy extendido para la generaci6n de

Caoitulo 10
contenido Web. La especificaci6n JSP 1.1 (Diciernbre de 1999) afiadi6 nuevas e irnportantes utilidades: fundarnentalrnente, la capacidad para escribir extensiones de etiquetas personalizadas. Si ya ha trabajado con pigina JSP, quizis se pregunte c u d es la diferencia entre JSP 1.2 y JSP 1.1, y c u d es la irnportancia de esa diferencia. A continuaci6n presentarnos un breve resurnen de las rnejoras y carnbios rnis relevantes. Si no ha trabajado con JSP 1.1, debe saltarse la siguiente secci6n.
0 JSP 1.2 adopta la plataforrna Java 2, rnientras que JSP 1.1 puede ejecutarse con Java 1.1 0 JSP 1.2 requiere la versi6n 2.3 del API Servlet (Las especificaciones JSP 1.2 y Servlet 2.3 han sido

desarrolladas de forrna paralela bajo JSR-053. Muy poca funcionalidad de JSP 1.2 requiere las rnejoras de Semlets 2.3. El apoyo para 10s "eventos de aplicaci6n Web" de Semlet 2.3 en extensiones de etiquetas de JSP 1.2 es un ejernplo.)
0 La acci6n estindar < j s p : i n c l u d e > ya no vacia el blifer antes de incluir. ~ s t es e un carnbio bien recibido porque este vaciado result6 ser una irnportante hrnitaci6n en JSP 1.1
0

Hay rnejoras irnportantes en el apoyo a la extensi6n de etiquetas. Facilitan el trabajo con el API de extensi6n de etiquetas e incorporan la opcion de una validacidn del period0 de traducci6n rnis sofisticada. La representaci6n XML de piginas JSP est6 rnis desarrollada y las rniquinas JSP son necesarias para aceptar la representaci6n XML de las piginas JSP asi corno las piginas JSP en la sintaxis habitual. Esto facilita la autornatizaci6n de la cornposici6n de piginas JSP y proporciona la base para un nuevo rnecanisrno de validaci6n para el uso de librerias de etiquetas personalizados.

0 Se ha ahadido un nuevo constructor a la clase JspException que perrnite la creaci6n de una excepci6n que alberga un rnensaje y una causa raiz Throwable (en lugar de un simple rnensaje). Esto supone que las trazas de pila pueden ser preservadas, facilitando la depuraci6n de aplicaciones utilizando el nuevo constructor.

La buena noticia es que JSP 1.2 es cornpletarnente compatible descendente. Con cada revisi6n de las especificaciones JZEE, el cuerpo de producci6n de soluciones J2EE crece y Sun lo ha asirnilado. Por ejernplo, aunque hay nuevos D T D para 10s descriptores de librerias de etiquetas, 10s contenedores son necesarios para apoyar el D T D de JSP 1.1. Los carnbios de API son tarnbikn compatibles descendientes, aunque ha habido algunas desaprobaciones. En conjunto, 10s carnbios son evolucionarios rnis que revolucionarios per0 ciertarnente notables y bienvenidos. JSP 1.2 es notablernente rnis capaz que JSP 1.1 per0 resulta rnis ficil trabajar con 61.

Presentacion de JSP
JSP, a1 igual que otros API de Java, es una especificaci6n proporcionada por Sun para que la irnplernenten 10s vendedores. La especificaci6n JSP se ahade a la funcionalidad proporcionada por la especificaci6n de servlet. Entonces, ien que se diferencian las piginas JSP de 10s semlets? Los senlets son respuestas de Java alas directivas CGI. Son rnis elegantes y se ejecutan rnejor que las directivas CGI. Se ejecutan en el semidor e interceptan solicitudes de navegador, actuando corno una especie de capa interrnedia entre clientes y aplicaci6n de rnenor nivel. Los semlets son adecuados para decidir c6rno rnanejar solicitudes de cliente e invocar otros objetos de lado servidor per0 no son tan adecuados para generar contenido. La experiencia ha dernostrado que la generaci6n de anotaciones a partir de c6digo Java es dificil de irnplementar y de rnantener. Los servlets deben ser escritos por desarrolladores farniliarizados con Java.

Fundamentos y arquitectura de JSP


Las piginas JSP, por otro lado, pueden ser disehadas y desarrolladas no tanto como programas sino mas como piginas Web. Las piginas JSP son ideales para situaciones en las que necesitamos mostrar anotaciones con contenido dinimico integrado. Sin embargo, aunque generar HTML es mucho mas ficil con JSP que con un servlet, las piginas JSP son menos adecuadas para manejar la ldgica de procesamiento. Las piginas JSP pueden utilizar JavaBeans con un alcance o extensiones de etiquetas especificados para alcanzar una clara separaci6n entre contenido esti tic0 y el c6digo Java que produce aplicaciones Web dinimicas. Esto permite que las piginas JSP Sean creadas y mantenidas por disehadores con aptitudes de presentacidn que n o necesitan tener conocimientos de Java. Aunque hay una coincidencia de capacidad, piense en 10s servlets como en objetos controladores y e n las piginas JSP como objetos de vista. N o piense que necesita elegir entre utilizar servlets y piginas JSP en una aplicaci6n Web; son tecnologias complementarias y una aplicaci6n Web compleja hari uso de ambas. Una simple pigina JSP que incluya la fecha de hoy en una pigina HTML sera asi:
< % @ p a g eirnport="java.util.Date"%> <htrnl> <body> The c u r r e n t t i m e i s <%= ( n e w D a t e ( ) ) .t o s t r i n g ( ) </body> </htrnl>

%>

Para ejecutar 10s ejemplos de este capitulo, necesitaremos crear una nueva aplicaci6n. Cree el directorio % J~EE-HOME%\ p u b l i c - h t m l \ J S ~ E x a m ~ l\. e Guardeelc6digodeejemplocomosimp~e s JSP. j s p en nuestro directorio fuente,% J2EE_HOME%\ C h l O \ J S P E x a m p l e s . Para desplegar esta aplicaci6n Web utilizando la Implementaci6n de Referencia (RI) J2EE, debemos primer0 iniciar el servidor J2EE. Copie entonces el archivo s i m p l e . j s p desde el directorio fuente en el d i r e c t o r i o \ p u b l i c - h t m l \ JSPExamples. Lo linico que tenemos que hacer ahora es navegar hasta http://localhost:800O/JSPExamples/simpleJSP.jsp y debemos poder ver algo similar a esto:

rr

Localintranet

La pigina JSP y 10s archivos dependientes son conocidos en conjunto como una unidad de traducci6n. La primera vez,que una miquina JSP intercepta una solicitud para una JSP, compila la unidad de traducci6n en un servlet. Este es un proceso de dos fases. El c6digo fuente JSP es convertido en un servlet y este servlet es entonces compilado. La Implementaci6n de Referencia almacena la fuente de servlet y el c6digo compilado en el directorio %~2~~~~0~~%\repository\<server~name>\~eb\~~~~xamples(~aparte<serv variari con el nombre de su ordenador) Aqui encontrari un archivo .j a v a y otro .c l a s s . El archivo .j a v a contiene el c6digo fuente para el servlet creado a partir de s i m p l e J s P .j s p .

Capitulo 10
La primera vez que una JSP es cargada por el contenedor JSP ( t a m b i h llamado rniquina JSP), el c6digo de servlet necesario para implementar las etiquetas JSP es automiticamente generado, compilado y cargado en el contenedor de servlet. Esto sucede en el periodo de traducci6n. Es importante destacar que esto s610 tiene lugar la primera vez que una pigina JSP es solicitada. La primera que se accede a una pigina JSP habri una respuesta Ienta pero, en posteriores solicitudes, el servlet compilado con anterioridad simplemente procesa las solicitudes. Esto ocurre en el periodo de ejecuci6n. Si modificamos el c6digo fuente para la JSP, este es automiticamente recompilado y recargado cuando esa pigina sea solicitada de nuevo. Detris de estos procesos suceden muchas cosas y nosotros, como desarrolladores, estamos recibiendo 10s beneficios en forma de ventajas de composici6n. (La miquina servlet gestionari normalmente esta situaci6n haciendo que la clase de servlet generada exponga una estampilla de tiempo. Antes de cada solicitud, la estampilla de tiempo puede compararse con la estampilla de tiempo de modificaci6n del sistema de archivos del archivo JSP. Seri necesario recompilar s610 si la estampilla de tiempo del archivo JSP es posterior a la estampilla de tiempo de la clase.)

Observe que para que la cornpilacidn sea efectiwa, u n compilador JSP debe estar disponible para la mkquina de sewlet durante el periodo de traduccidn. Remitase a la documentacidn de su maquina de sewlet para comprobar si es necesario tomar medidas adicionales para configurarla. Por ejemplo, en el sewidor Orion, el archivo t 001s. j a r debe ser copiado de la distribucidn J D K en el directorio raiz del sewidor. Muchos sewidores (como Jrun y WebLogic) cuentan con un compilador como parte integrante de la distribucidn.
La distinci6n entre periodo de traducci6n y periodo de ejecuci6n es muy importante para comprender como funcionan las piginas JSP puesto que esta terminologia sera utilizada en prdximos capitulos. Esta figura resume el proceso:

4 <etlquetasJSP>
Utl'lza

JSP

<c6d1go lava>

JSP

Cl~ente
1 -

Genera Respuesta
-

Sollc~tudesposterlores procedentes de cualqu~er chente son manejadas por el servlet

--

- -

.-

Esta figura tambien muestra c6mo una pigina JSP puede invocar dinimicamente otras piginas JSP. Para el cliente, esto es transparente; parece que la pigina JSP original ejecuta todo el procesamiento. Una pigina JSP puede invocar otra pigina JSP (o cualquier otro recurso dentro de la aplicaci6n Web actual) porque el servlet generado tiene acceso a] mecanismo Request Dispat cher.

Fundamentos v arquitectura de JSP


La clase servlet generada a1 final del proceso de traducci6n representa la relaci6n perfectamente definida entre un contenedor y una pigina JSP. Segun la especificaci6n JSP, que implementa el contenedor, la clase servlet debe ampliar una superclase que es una de las siguientes dos opciones:
0 Una clase de implementation especifica de un contenedor JSP que irnplementa la interfaz j a v a x s e r v l e t . j sp.JspPage y proporciona algun comportamiento bisico especifico de la pigina. (Puesto que la mayoria de las piginas JPS utiliza HTTP, sus clases de implementaci6n debe en realidadimplementarlainterfaz j a v a x . s e r v l e t . j s p . H t t p J s p P a g e , quearnpliaasuvez j a v a x . s e r v l e t .j s p . ~ s p ~ a g e ) .

Una superclase especificada por el autor JSP mediante un atributo extends en la directriz de la pigina.

La interfaz j a v a x . s e r v l e t j s p . J s p P a g e contiene dos mitodos:


public void jspInit ( )

Este mitodo es invocado cuando la pigina JSP es inicializada y es anilogo al mitodo i n i t ( ) de 10s servlets. Los autores de la pigina pueden proporcionar la inicializaci6n de la JSP implementando este metodo en sus piginas JSP.
public void jspDestroy
()

Este mitodo es invocado cuando la JSP esti a punto de ser destruida por el contenedor y es anilogo al metodo d e s t r o y ( ) de 10s servlets. Los autores de piginas pueden establecer la lirnpieza de JSP implementando este metodo en sus piginas JSP. Lainterfaz j a v a x . s e r v l e t j s p . H t t p J s p P a g e c o n t i e n e u n ~ n i c o m ~ t o d o :
public void -jspService(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException

Este metodo corresponde a1 cuerpo de la pigina JSP y es utilizado para el procesamiento de solicitudes enhebradas, igual que el metodo s e r v i c e ( ) de 10s servlets.

La implementaci6n de este mitodo es generada por el contenedor y nunca debe ser proporcionada por 10s autores de pigina.
Estos tres importantes metodos de vida funcionan juntos en una JSP, como vemos a continuaci6n:

Dara todas las sol~citudes. para la prlmera solicitud

para limpiar JSP

o La pigina es primer0 inicializada invocando el mitodo j s p I n i t ( ) ,que puede ser definido por el
autor de la pigina. Esto inicializa la JSP del mismo modo en que son inicializados 10s servlets, cuando la primera solicitud es interceptada y justo despues de la traducci6n.
L I

Cada vez que se realiza una solicitud a la JSP, el metodo JSP p a g e s e r v i c e ( ) generado por el contenedor es invocado, la solicitud es procesada y la JSP genera la respuesta adecuada. Esta respuesta es tomada por el contenedor y pasada de vuelta a1 cliente.

0 Cuando la JSP es destruida por el servidor (por ejemplo, en el cierre), el metodo j s p D e s t r o y ( ) , que puede ser definido por el autor de la pigina, es invocado para realizar cualquier limpieza.

Capitulo 10
Observe que, en la rnayoria de 10s casos, 10s rnttodos j s p I n i t proporcionados por el autor JPS y puede ser ornitidos.
()

y j s p D e s t r o y ( ) no necesitan ser

Los aspectos practicos


Analicernos ahora 10s elernentos que constituyen una pigina JSP. La estructura de una pigina JSP es un cruce entre un servlet y una pigina Web estitica, con cddigo Java adjunto entre las construcciones < % y % > y otras etiquetas tip0 XML intercalados. Existen tres categorias de etiquetas JSP:
0 Directrices afectan a1 conjunto de la estructura del servlet que resulta de la traducci6n per0 ellas misrnas no producen inforrnaci6n de salida.

sta as

Elementos de directiva Estos elernentos nos perrniten insertar c6digo Java en la pigina JSP (y, de este rnodo, en el sewlet resultante). Acciones Estas son etiquetas especiales disponibles para alterar el cornportarniento del period0 de ejecuci6n de la pigina JSP. JSP provee algunas acciones esdndar, corno <jsp:useBeans>, que tratarernos rnis adelante en este capitulo y que pueden escribir nuestros propias etiquetas. Estas acciones personalizadas son norrnalrnente conocidas corno extensiones de etiqueta o etiquetas personalizadas. Hay algunas reglas generales que se aplican a las piginas JSP:
0

Las etiquetas JSP, corno las etiquetas XML, son sensibles a caja.

0 Las directrices y elernentos de directivas tienen una sintaxis que no esti basada en XML per0 tarnbien hay una sintaxis alternativa a XML disponible. Sin embargo, esto no esti destinado a la cornposici6n manual sin0 rnis bien a piginas JSP creadas por software especializado.
0

Las etiquetas basadas en sintaxis XML tienen una etiqueta de inicio con atributos opcionales, un cuerpo opcional y una etiqueta final concordante; o bien tienen una etiqueta vacio, posiblemente con atributos.

<mylibrary:somejsptag attributename="attribute value"> body </mylibrary:somejsptag>

<mylibrary:somejsptag

attributename="attribute value"

/>

En texto plantilla, un <% literal, que iniciaria en otro caso un elernento de directiva, es entrecornillados corno <\%; un %> literal, que finalizaria en otro caso el elernento de directiva, es entrecornillado corno %\>. Los valores de atributo en etiquetas siernpre aparecen entrecornillados, corno el XML. Pueden utilizarse tanto cornillas dobles corno sencillas. Las cadenas especiales Lapos; y ~ q u o tpueden ; utilizarse (corno en HTML) si las cornillas estin contenidas en el valor atributo.

CI Cualquier espacio en blanco dentro del texto del cuerpo de un docurnento no es significativo per0

se rnantiene durante la traducci6n a un servlet.

Fundamentos y arquitectura de JSP

Los URL utilizados por las piginas JSP siguen convenciones de servlet y un URL que ernpiece con

/, denorninado ruta relativa a1 contexto, es interpretado con referencia a la aplicacidn Web a la que
pertenece la pigina JSP. (El s e r v l e t c o n t e x t esti disponible corno objeto irnplicito en piginas JPS, corno verernos rnis adelante.)
0 Si el URL no ernpieza con /, es interpretado con relacidn a la actual JSP.

Las convenciones para URL relatives son las rnisrnas porque tanto las piginas JSP corno 10s servlets pueden desplegados en aplicaciones Web.
N o caiga en la tentaci6n de desplegar aplicaciones corno un conjunto de pciginas JSP en el sistema de archivos bajo la raiz de documento de su sewidor; una aplicaci6n Web es una unidad esta'ndar de despliegue apoyada por todos 10s servidores adaptados y resuelve estos temas (por otro lado espinosos) corno las rutas de clase de aplicaci6n y las asociaciones de URL virtuales piblicos a recursos de aplicaci6n.

Directrices JSP
Las directrices JSP configuran la generacidn de c6digo que ejecutari el contenedor a1 crear un servlet. Son utilizadas para establecer valores globales tales corno declaraciones de clase, rnetodo a irnplernentar, tip0 de contenido de salida, etc., y no producen ninguna salida para el cliente. Las directrices tienen alcance para el total de la pigina JSP; en otras palabras, una directriz afecta a toda la pigina JSP per0 s61o a esa pigina. Las y la sintaxis general es: directrices cornienzan con < %@ y finalizan con %>
<%@ directivename

attribute="valueM attribute="valuen %>

Hay tres directrices principales que pueden ser utilizadas en una JSP:

u La directrizpage
0
O

La directriz i n c l u d e Ladirectriztaglib

La directriz page
La directriz p a g e es utilizada para definir y rnanipular una serie de atributos irnportantes que afectan a1 conjunto de la pigina JSP. Una pigina puede contener cualquier nGrnero de directrices p a g e , en cualquier orden, en cualquier lugar de la pigina JSP. Todas son asirniladas durante la traduccidn y aplicadas en conjunto a la pigina. Sin embargo, s61o puede haber un ejernplar de cualquier par valor-atributo definido por las directrices de la pigina en una deterrninada JSP. Una excepcidn a esta regla es el atributo i m p o r t ; puede haber rnGltiples irnportaciones. Por convencidn, las directrices page aparecen a1 principio de una pigina JSP. La sintaxis general de la directriz de pigina es la siguiente:
<%@ page

ATTRIBUTES %>

Donde 10s atributos vilidos son 10s siguientes pares de valor nornbre:

Capitulo 10
Atributo Language Descripci6n Define el lenguaje de directivas a utilizar. Este atributo existe en el caso de que futuros contenedores apoyen multiples lenguajes. El valor es un nombre de clase corn letamente calificado de la superclase ue la clase genera a, en la que se traduce esta pigina JSP, ebe ampliar. Valor p o r defect0 Java

extends

Omitido por defecto

Este atributo debe ser evitado normalmente y s610 debe ser utilizado con extrema precaucibn, porque las m i uinas JSP proporcionan habitualmente su ercyases e~~ecializadaa con mucha funcionalidad que degen ser ampliadas por las clases de servlet generadas. El uso del a t r ~ b u t o e x t e n d s restringe algunas de las decisiones que un contenedor JSP puede tomar. import Lista de paquetes o clases separada por comas, con el mismosign~ficado que las instrucciones i m p o r t en las clases Java. Especifica si la pigina participa o no en la sesi6n HTTP. Cuando la respuesta es t r u e , el objeto implicito llamado sesi6n, que hace referencia a j a v a x .s e r v l e t .h t t p . ~ t te s ps i o ~ n , esti disponible y puede ser utilizado para acceder a la sesi6n nueva/actual para la pigina. Si la respuesta es false, la pigina no participa en una sesi6n y el objeto sesi6n implicito no esti disponible. Especifica el modelo de bufer para la corriente de salida a1 cliente. Si el valor es none, no tiene lugar la buferizaci6n y toda la informaci6n de salida es escrita directamente a travks de S e r v l e t R e s p o n s e por un P r i n t w r i t e r . Si se especifica un tamafio de bGfer (por ejemplo, 24kb), la 1nformaci6n de salida es buferizada con un tamafio de b6fer que no debe ser inferior a ese valor. Omitido por defect0

session

True

buffer

Dependiente de implementaci6n; como minimo 8kb

auto Flush isThre adSaf e

Si es t r u e , el bufer de salida a1 cliente es automiticamente True vaciado cuando esti lleno. Si es false, surge una excepci6n de period0 de ejecuci6n para indicar un desbordamiento de bufer. Define el nivel de seguridad de hilo implementado en la pigina. Si el valor es t r u e , la miquina JSP puede enviar m6ltiples solicitudes de cliente a la pigina a la vez. Si el valor es f a l s e , entonces el contenedor JSP acopla solicitudes de cliente enviadas a la pigina para su procesamiento y las procesa una a una sucesivamente, en el orden en que han sido recibidas. Es igual que implementar la interfaz j a v a x . s e r v l e t . Single~hreadModelenunservlet. True

info

Define una cadena informativa que puede ser obtenida posteriormente a partir de la implementaci6n de la piginadelmktodo~ervlet. g e t s e r v l e t I n f o 0.

Omitido por defect0

Fundamentos v arquitectura de JSP


Atributo error Page Descripcih Valor por defect0

Define un URL a otra pigina JSP dentro de la aplicaci6n Ornitido por defect0 Web actual, que es invocada si se lanza una exce ci6n verificada o sin verificar. La irnplernentaci6n de Pa pigina captura la instancia del objeto T h r o w a b l e y la pasa a1 procesarniento de la pigina de error. El rnecanisrno de p i ina de error es rnuy Gtil y evita la necesidad de que lor desarrok~adores escriban c6digo para ca turar excepciones irrecuperables en su p i g h a J ~~ k~ a s el e . atriuto i s E r r o r Page. Indica si la agina JSP actual esti destinada a ser otra pigina de error d e g pigina JSP. false

isError Page

Si es t r u e , entonces la excepci6n variable irnplicita esti disponible y hace referencia a la instancia de j a v a .l a n g . T h r o w a b l e lanzada en el period0 de ejecuci6n por la JSP que provoc6 el error.
content Type Define la codificaci6n de caracteres para la pigina JSP y el tipo MIME para la respuesta de la pigina JSP. ~ s t puede e tener la forrna "MIMETYPE oMIMETYPE; c h a r s et=CHARS ET con un espacio blanco opcional despuks de
'I;".

El valor por defecto para MIMETYPE es text/html;elvalor por defecto para CHARS ET es ISO-8859-1

CHARS ET, o codificaci6n de caracteres si se especifica, debe ser el valor IANa para una codificaci6n de caracteres. Los atributos no reconocidos tienen corno resultado errores fatales de traducci6n. La siguiente pigina JSP, p a g e D i r e c t i v e . j s p , contiene una directriz p a g e de atributo rico:
< % @ page

language="Java" i m p o r t = " j a v a . r m i . * , j a v a . ~ t i l . ~ session="true" buffer="12khW autoFlush="truen info="my page directive j sp" errorPage="error. j sp" isErrorPage="falseW isThreadSafe="trueM % > <html> <head> <title>Page directive test paye</title> </head> <body> <hl>Page directive test page</hl> This is a JSP to test the page directive. </body> </html>

La directriz include
La directriz i n c l u d e instruye a1 contenedor para que incluya el contenido de un recurso en la JSP actual, insertindolo en-linea, en la pigina JSP, en lugar de la directriz. El archivo especificado debe ser accesible y estar disponible para el contenedor JSP. La sintaxis de la directriz i n c l u d e es:
< % @include

file="Filenameu %>

El Gnico atributo disponible, f i l e , especifica el nornbre fichero del archivo a incluir. ~ s t es e una ruta relativa dentro del archivo WAR actual, que cornienza por una barra diagonal. Fijese en que no es

Capitulo 10
necesariamente un URL public0 dentro del WAR, puesto que la directriz i n c l u d e tiene acceso a todos 10s archivos dentro de WAR, incluso aquellos que no son publicamente visibles. El contenido incluido necesario no siempre es necesario que sea una JSP; puede incluir fragmentos HTML, o incluso otro recurso de texto. Los siguientes son ejemplos de nombres de fichero vilidos:
O

/debug. j s p Esto incluiri 10s contenidos del archivo d e b u g . j s p del directorio raiz del WAR.
(WEB-INF/templates/standarFooter.html Este inchiriel a r c h i v o s t a n d a r ~ o o t e . rh t m l del directorio /WEB- I N F / t e m p l a t e s del WAR. Este archivo no puede ser solicitado directamente puesto que la miquina de senlet n o publica todo lo que se encuentra dentro del directorio WEB-INF.

El contenido del archivo incluido es analizado por la JSP s610 en periodo de traduccio'n, es decir, cuando la pigina JSP es compilada en un senlet.
La accio'n include es utilizada para incluir recursos en el periodo de ejecucio'n, como veremos mds adelante.

La mayoria de 10s contenedores JSP registrarin el archivo incluido y recompilarin la piginaJSP si &a cambia. Sin embargo, puede que el contenedor elija n o realizar estas acciones.
Puesto que la compilaci6n del archivo incluido no tend& lugar hasta que este archivo haya sido incluido en el contexto de otra JSP completa, el archivo incluido no necesita ser una JSP vilida. Quizis, por ejemplo, confie en las importaciones o en 10s beans que no declara. En tales casos, debemos seguir las siguientes convenciones:
O

Utilizar una extensi6n que no sea JSP para el archivo incluido. La especificaci6n JSP recomienda que utilicemos . j s p f o . j s f . publicamente visible, para evitar que 10s usuarios del sistema 10s soliciten directamente. Cualquier ubicacion en el directorio WEB- INF (corno hemos mostrado en el segundo ejemplo anterior) seri, valido: nuestra miquina de senlet no publicari contenido que se encuentre en este directorio, aunque 10s archivos situados en 61 seguirin siendo visibles para la directriz i n c l u d e .

0 Situar fragmentos de pigina incompletos en un directorio de nuestra aplicaci6n Web que no sea

0 Documentar cualquier requisito de contexto de su fragment0 de pigina (corno suposiciones de

variable e importaci6n) en un comentario de cabecera JSP.

El archivo i n c l u d e puede ser un archivo estitico (corno un archivo HTML) u otra pigina JSP. En cualquier caso, el resultado sera el mismo que si el total del contenido del archivo hubiera sido introducido en la pigina JSP de inclusi6n en lugar de la directriz JSP. El siguiente ejemplo, i n c l u d e D i r e c t i v e 1 . j s p , solicita la inclusi6n, durante la compilaci6n, de un archivo copyright que contenga salvedades legales escritas en HTML:
<htrnl> <head> <title>Include directive test page l</title> </head> <body> <hl>Include directive test page l</hl> < % @ include file="/JSPExarnples/copyright.html" </body> </html>

%>

Fundamentos y arquitectura de JSP


El archivo c o p y r i g h t . h t d contiene lo siguiente:

C o p i e a m b o s archivos en el d i r e c t o r ~ o J 2 E E HOME \public-html\ J S P E x a m p l e s . Navegue entonces hasta h t t p : / / l o c a l h o s t : 8 0 0 0 / ~ ~ ~ E x a m p l e s / ~ n c ~debemos 1 . ] s p ; ver algo parecldo a estb:

/
IH

0 200 1 Wron Press


ist to

'B Locd intrmet

El biguiente ejemplo muestra c 6 m o una pigina JSP puede ser incluida. Corisidere el archivo includeDirective2.jsp:
c h tml>
-.'head>

, : t i t l e ' . I n ~ l ~ ~ dd ei r e c t i v e t e s t p a g e 2 i / t i t l e ? </head> <bc,dv.* -'hl:.Tr~cl~ude d i r e c t i v e t e s t p a g e 2c:/hl? < % I ? i n c l u d e f i l e = " / J S P E x a r n p l e s / i r 1 ~ 1 ~ ~ 3jesp" d.


</bc,dy>

%>

.'/html.>

El c6digo para el archivo i n c l u d e d . j s p d e JSP incluido es el siguiente:

Guarde ambos archivos e n el directorio J S P E x a m p l e s . U n a vez copiados, navegue hasta http:// localhost:8000/JSPExamples/includeDirectve2sp; debe poder ver alga asi:

Include directive test page 2


Current date is Mon Aug 13 22 0239 BST 2001

r' @ Local

A
intranet

Capitulo 10
Cuando i n c l u d e D i r e c t i v e 2 .j s p es traducido, laparte incluida delcodigo de servlet, despojada de comentarios, tiene este aspecto:
out.write("<htrnl>\r\n <head>\r\n <title>Include directive test page 2</title>\r\n </head>\r\n <body>\r\n <hl>Include directive test page Z</hl>\r\n\r\n " 1 ; out.write("\r\n"); out.print ("Current date is " + n e w D a t e ( )) ; out .write( " \ r \ n M ) ; . oot . w r i t e ( " \ r \ n </body>\r\n</htrnl>\r\nt');

Podernos ver que el c6digo del archivo incluido ha sido incluido en-linea en el c6digo de servlet.

La directriz taglib
La directriz t a g l i b permite a la pigina utilizar extensiones d e etiqueta (etiquetas personalizadas). Denomina la libreria de etiquetas que contiene c6digo Java que define las etiquetas que deben ser utilizados. La maquina utiliza esta libreria de etiquetas para saber qu6 hacer cuando se encuentra con etiquetas personalizados en la JSP. La sintaxis de la directriz t a g l i b es la siguiente:
< % @taglib

uri="tagLibraryURIfl prefix="tagPrefixV %>

Y 10s atributos disponibles son:

Atributo

Descri~ci6n U n URI (Identificador de Recurso Uniforrne) que identifica el descriptor de libreria de etiqueta. U n descri tor de llbreria de eti ueta es utilizado para nomfrar exclusivamente e grupo de etiquetas ersonalizados e indica a1 contenedor qu6 hacer con Pas etiquetas especificados.

Valor or defect0 N o hay valor por defect0 La no es ecificaci6n de un va or provoca un error de compilaci6n.

tagpref i x

Define la cadena de prefijo en p r e fix:tagname que es utilizado para definir la etiqueta personalizado.

N o hayvalor ordefecto. La no especi&aci6n de un valor provoca un Los prefijos j s p , j s p x , j a v a , j a v a x , s e r v l e t , error de compilaci6n. s u n y s u n w son reservados.

Si este valor es m y t a g entonces, cuando el contenedor se encuentra cualquier elernento ue empiece corno < m y t a g : t a g n a m e . . . I >en?, SP, re refiere a1 descriptor de libreria de etiqueta especi lcado en el URI.

{.

Las librerias de etiquetas son una funci6n rnuy importante de JSP.

Elementos de directivas
Los elementos de directivas de JSP permiten c6digo Java: declaraciones de variables o de metodo, scriptlets (bloques de c6digo Java evaluados en el orden en que aparecen a rnedida que la pigina reciba la solicitud) y expresiones (para ser insertadas en nuestra pigina JSP).

482

Fundamentos v arauitectura de JSP Declaraciones


Una declaraci6n es un bloque de c6digo Java es una JSP que es utilizado para definir variables y metodo de clase en el servlet generado. Las declaraciones son inicializadas cuando la pigina JSP es inicializada y tienen alcance instanciado en el servlet generado, por lo que cualquier elemento definido en una declaraci6n esti disponible en JPS para otras declaraciones, expresiones y c6digo. U n bloque de declaraciones estj. encerrado entre <%! y %> y n o escribe ninguna informaci6n en la corriente de salida. La sintaxis es:
< % ! Java variable

and method declarations %>

Considere esta sencilla J S P , d e c l a r a t i o n . j s p :

p u b l i c S t r i n q s a y H e l l o [ S t r i n g name) r e t u r n " H e l l o , " t name + ' I ! " ;


%

>

<html> <head> <titla>Declaration test page</title> </head> <bs?dy> <hl>Declaration t e s t page</hl> i p > T h e v a l u e o f numTimes i s < % = numTimes % > . < / p > < p > S a y i n g h e l l o t o r e a d e r : " < % = s a y H e l l o ( " r e a d e r " ) %>".</p> </body> </htrnl>

~ s t declara a unavariable i n t llamadanurn~irnes y un metodo s a y H e l l o ( ) que saluda a la persona solicitada. Mas adelante en la misma pigina, se utilizan elementos de expresi6n (que verernos a continuaci6n) para devolver el valor de nurnTirnes a1 navegador e invocar el metodo s a y H e l l o ( ) . G u a r d e d e c l a r a t i o n . j s p en el directorio ~ s p ~ x a r n p lyevea s http://localhost:800O/JSPExamples/ decalration.jsp; veri entonces la siguiente pantalla:

Declaration test page


The value of numTmes IS 3
Saying hello to reader "Helo, readerl"

m s o ~ t l

prI@

rl
L O ~intranst I

Capitulo 10
El servlet generado contiene el siguiente codigo de declaraci6n:
import

//

...

j a v a x . s e r v l e t . i; m6s i n s t r u c c i ~ i r , e s d e class

importaci6n HttpJspBace
{

public

O O O Z f d e ~ l a r a t i o r ~ ~ je sx pt e n d s

p u b l i c S t r i n g . s a y H e l l o ( S t r i n g name) r e t u r r , " H e l l o , " + name + " ! " ;

//

...

Mis

cbdlgo

generada

Observe que el c6digo de la declaraci6n de JSP no esti localizado en el mttodo -j s p s e r v i c e ( ) del servlet generado sino que esti directamente insertado en la clase misma, para definir las variables estiticas o de instancia y mttodos.

Scriptlets
U n scriptlet es un bloque de c6digo Java que es ejecutado durante el period0 de procesamiento de solicitud y esti encerrado entre etiquetas < %y %>.Las funciones exactas del scriptlet dependen del mismo c6digo y pueden incluir producir informacih de salida para el cliente. Miiltiples scriptlets son combinados en la clase de servlet generada en el orden en que aparecen en la JSP. Los scriptlets, como cualquier otro bloque o metodo de c6digo Java, pueden modificar objetos dentro de ellos como resultados de invocaciones de mttodos. En la Implementation de Referencia, todo el c6digo que aparece en entre etiquetas < %y % >en la JSP es situado en el mttodo s e r v i c e ( ) del servlet y en el orden en que aparece. Es, por lo tanto, procesado para cada solicitud que recibe el servlet. La sintaxis para scriptlets es la siguiente:
<%

Valid Java code statements %>

En el ejemplo que mostramos a continuation, s c r i p t l e t . j s p , un scriptlet ejecuta un ciclo diez veces. Inchye un mensaje cada vez en el html enviado al navegador, utilizando el objeto implicito o u t . Tambikn envia cada mensaje a la corriente s y s t e m . o u t , es decir, a la ventana de la consola en la que se esta eiecutando RI:
<htrnl> <head> <title>Scriptlet test page</title> </head> <body> < h l > S c r i p t l e t t e s t page</hl>

<%
f o r ( i n t i=O;i< 1 0 ; i + + ) { o u t . p r i r ~ t l n ( " < b > H e l l oW o r l d . T h i s i s a . s c r i p t l e t t e s t " " < / b > < b r > ") ; Systern.out.printlr~("This g o e s t o t h e S y s t e m . o u t s t r e a m
t
"

+ i);

Fundamentos y arquitectura de JSP


Guarde script1et.j~~ en el directorio JSPExamples, afiada el archivo al directorio h~2~~~~0~~~\~ublic~html\~~~~xamplespso~ic~tehttp://localhost script let. j sp. La salida de la ventana del navegador debe ser la siguiente:
-:ti,
--

Arch~vo Edlch
-

Vsr

Fwortos
-

Herramlentas

Ayuda *m,to5
-- ---

, A

- 3
-

a~kqueda
-

g~dtL-ia

---

3 1 6; d) --- - -

im
-

Scriptlet test page


Hello World. This is a scriptlet test 0 Hello World. This is a scriptlet test 1 Hello World. TIUSis a scriptlet test 2 Hello World. This is a scriptlet test 3 Hello World. This is a scriptlet test 4 Hello World. This is a scriptlet test 5 Hello World. This is a scriptlet test 6 Hello World. Tlus is a scriptlet test 7 Hello World. Tlus is a scriptlet test 8 Hello World. This is a scriptlet test 9

q ist to

r@j

~ocal intranet

y la siguiente informaci6n debe aparecer en la ventana de la consola donde se ejecuta el servidor J2EE:

Los scriptlets pueden romperse por contenido estitico, siempre que se utilicen en ellos instrucciones compuestas y que la estructura de llaves sea 16gica. Por ejemplo, el siguiente fragment0 de c6digo (basado en un ejemplo posterior de este capitulo) muestra el uso de un scriptlet para manejar el flujo de control

485

Capitulo 10
rnientras se utiliza la sintaxis JSP en el scriptlet para producir contenido. El desarrollador de prograrnas para desplazarse entre un scriptlet Java y contenido JSP normal segGn puede utilizar las etiquetas < %y % > su voluntad. N o existen restricciones en el c6digo JSP que puedan aparecer en 10s scriptlets (pueden utilizarse otros scriptlets, acciones, directivas, expresiones y datos de plantilla).
<%
i f
%

( " R i c h a r d " . e q u a l s ( r e q u e s t. g e t p a r a m e t e r ("userNarnel')) )

>
Richard.
{

Hello
<%

You're

logqed

in.

1 else

%>

You're not Richard. Your u s e r name i s < % = r e q u e s t . g e t p a r a m e t e r ( " u s e r N a r n e e ' ) % >

Observe que un c6digo corno el del siguiente ejernplo de uso incorrect0 de scriptlet no funcionari corno espera:

Hello

Richard.

You're

logged

i n

Debido a que la instruccion i f no utiliza una instrucci6n cornpuesta (es decir, no tiene {), la instruccion ejecutada si la condicion i f es t r u e seri probablernente la instruccibn de servlet o u t . p r i n t I n ( ) generada para preservar el espacio en blanco despues del scriptlet y la linea de scriptlet no sirve para rnanejar el f h j o de control. Siernpre verernos " H e l l o R i c h a r d . You' r e l o g g e d in". (Por cierto, las convenciones de c6digo Java de Sun recorniendan el uso de instrucciones cornpuestas, siernpre que sea posible, para evitar este tip0 de error en el codigo Java.) Este uso de scriptlets y contenido JSP se encuentra con frecuencia en JSP. Los desarrolladores confunden a rnenudo declaraciones y scriptlets. Una declaration utiliza la sintaxis <%! y define variables y rnetodos de alcance de instancia. U n scriptlet define variables de c6digo de alcance local a1 rnCtodo - j s p s e r v i c e ( ) . Esto significa que las variables y 10s mCtodos estiticos solo pueden ser definidos en declaraciones. Tarnbien significa que se puede acceder a las variables definidas en declaraciones desde rndtiples hilos. Igual que en el caso de variables de instancias, la seguridad de 10s hilos es un terna a tener en cuenta. Los scriptlets n o suponen ningun problerna de seguridad de hilos. Por lo tanto, n o utilice declaraciones sin una buena raz6n. Las declaraciones son a rnenudo utilizadas para un mayor rendirniento. P o r ejernplo, si una variable de solo lectura es costosa de inicializar, tiene sentido que la inicializaci6n tenga lugar una vez en la vida de la pigina JPS, en lugar de una vez por solicitud.

Expresiones
Una expresi6n es una notaci6n taquigdfica para un scriptlet que envia el valor de una expresi6n Java de vuelta a1 cliente. La expresi6n es evaluada en el period0 de procesarniento de la solicitud HTTP y el resultado es convertido en una s t r i n g y presentado. Una expresi6n aparece encerrada entre etiquetas < % = y % >. Si el resultado de la expresi6n es un objeto, la conversi6n es realizada utilizando el rnetodo t o s t r i n g ( ) del objeto. La sintaxis es:
<%= Java expression

to b e evaluated %>

Fundamentos v arquitectura de JSP

Considere el siguiente ejemplo JSP, guirdelo como e x p r e s s i o n . j s p en el directorio Js PExamples. Esta pigina JSP establece un sencillo contador y desmuestra c6mo declaraciones, scriptlets y expresiones trabajan juntas:
<html>

<head> <title>Expression test </head>


<body>

page</title>

<hl>Expression test page</hl>


<%! i n t

i=O

: %>

Hello W o r l d ! < % = "This JSE' h a s beer1 a c c e s s e d " t i

" times"

%?

Se declara una variable i n t i e inicialmente tiene el valor 0.Cada vez que es invocada la instancia del sendet generado, por ejemplo cuando el navegador solicita http://localhost:800O/JSPExamples/ expression.jsp, la variable es incrementada por el scriptlet. Finalrnente, una expresi6n es utilizada para imprimir el valor de i,junto con parte del texto circundante. Despuis de que esta JSP haya sido solicitada siete veces, el navegador rnostrarl lo siguiente:
-

Archlvo

Edtc61-1
--

Ver

Favorltos

Herrarmentas -- --

Ayuda

--

,InlA

II

Expression test page


Hello World! This JSP has been accessed 7 times

,&ist to

-1

II
~ o c intranet d

Observe que mientras que el c6digo de 10s scriptlets sigue una graniltica Java habitual, terminando las instrucciones con un punto y coma; sin embargo, una expresi6n JSP no terrnina con un punto y coma.

Comentarios
JSP perrnite comentarios ocultos. Cualquier contenido ubicado entre 10s delimitadores <%- y - % > serl ignorado por el contenedor en el period0 de traducci6n. Los comentarios JSP no anidan por lo que cualquier contenido except0 aqud que terrnine por-E> es legal en comentarios JSP.

Si deseamos ver comentarios en la salida generada, siempre podemos utilizar comentarios HTML o XML con 10s delimitadores < ! - y ->; estos serin tratados simplemente como datos normales de plantilla por el contenedor. Podemos utilizar 10s comentarios JSP para documentar detalles de nuestra implementation como hacemos en el c6digo Java. Sin embargo, podriamos optar por utilizar comentarios JSP en lugar de comentarios HTML para documentar tambien nuestra estructura de anotacion. Esto significa que podemos ser tan prolijos como queramos sin inflar el contenido generado. Tambien tenemos libertad para utilizar la sintaxis estindar de comentarios de Java en 10s elementos de scriptlet de Java.

Acciones estandar
Las acciones estindar son conocidas etiquetas que afectan a1 rendimiento del periodo de ejecucion de JSP y a la respuesta enviada de vuelta a1 cliente. Deben ser implementadas para funcionar del mismo mod0 en todos 10s contenedores. A diferencia de las etiquetas personalizados, estas acciones estin disponibles por defect0 y n o requieren declaraciones taglib para utilizarlas. Cuando el contenedor se encuentra con una etiqueta de acci6n estindar durante la conversion de una pigina JSP en jun sewlet, genera el codigo Java que se corresponde con la tarea predefinida solicitada. Por ejemplo, cuando se encuentra con la accion estindar include:
<j s p : include paqe="rnyjsp. j s p "
flush="trueW />

Incluye la salida producida por una solicitud con 10s mismos parimetros para myj s p j s p en la respuesta, en lugar de la etiqueta de acci6n. Las acciones estindar sirven para proporcionar a 10s autores de las piginas la funcionalidad bisica para explotar tareas comunes. Los tipos de acci6n estindar son 10s siguientes:

Para separar el c6digo de la presentation, es a menudo una buena idea encapsular la logica en un objeto Java (un JavaBean) e instanciar y utilizar entonces este objeto en nuestra JSP. Las etiquetas <jsp:useBean>,<jsp: setProperty>y<jsp:get~ro~erty>colaboranenestatarea. La accion < j s p :us eBean> es utilizada para instanciar un JavaBean o para localizar una instancia bean existente y asignarla a un nombre de variable ( o i d ). Tambien podemos especificar la vida de un objeto otorgindole unalcance especifico. < j s p :useBean> certifica que el objeto esti disponible, con el id especificado, en el alcance apropiado tal y como esti especificado en la etiqueta. El objeto puede ser entonces referenciado utilizando su id asociado desde la pigina JSP o incluso desde otras piginas JSP, dependiendo del alcance del JavaBean.

Fundamentos y arquitectura de JSP


Existen dos forrnas de sintaxis paralaetiqueta de acci6n< j s p : u s e g e a n > . La rirneranocontienecuerpo y sirnplernente hace que el objeto estk d~sponible para el resto de laPigina jsP: < j s p : u s e B e a n id="nameU scope="scopeName" b e a n - d e t a i l s

/>

La segunda forrna contiene un cuerpo que seri evaluado si el bean es instanciado. El cuerpo puede contener cualquier contenido JSP per0 norrnalmente consiste en scriptlets y acciones < j s p : s e t p r o p e r t y > , que configurael nuevo bean: < j s p : u s e B e a n id="nameM scope="scopeName" b e a n - d e t a i l s > Body < / j s p :u s e B e a n > Donde b e a n - d e t a i l s es uno de 10s siguientes:
0 0 0 0

class="className" c l a s s = " c l a s s N a m e " type="typeName" beanName="beanName" t y p e = " t y p e N a m e W type="typeNameW

Los posibles atributos son 10s siguientes:


--

Atributo id

Descripcibn El nornbre sensible a la caja utilizado para identificar la instancia de objeto. Si el bean ha sido creado por un servlet y puesto a disposici6n de la pigina JSP utilizando el rnetodo eliddeIaacci6n< j s p : u s e B e a n > s e t A t t r i b u t e 0, debe coincidir con el nornbre dado al atributo.

Valor por defecto N o hay valor por defecto

scope

El alcance en el que esti disponible la referencia. Los valores posibles son " p a g e " , " r e q u e s t " , "session", o" application". El nornbre de clase cornpletarnente cualificado. El nornbre de un bean, corno proporcionarernos a1 m e t o d o i n s t a n t i a t e ( ) enlaclase j a v a . b e a n s . B e a n s . Este atributo tarnbikn puede ser una expression de tiernpo de solicitud. Es perrnisible roveer un tipo y un beanName y ornitir el atributo de ifase. El beanName sigue la especificaci6n bean estindar y puede tener la forrna de a . b c , donde a.b.c es una clase o el nornbre de un recurso serializado, en cuyo caso es resuelto corno "a / b / c .s e r n . (Vkase la especificaci6n de JavaBeans para rnis detalles.) N o hay valor por defecto N o hay valor por defecto

class bean Name

type

Este atributo opcional especifica el tip0 de lavariable de directivas a crear y se ajusta a las norrnas estindar de asignaci6n de Java. El tipo debe ser una superclase de la clase bean, una interfaz ~rnplernentada por ella o la misrna clase bean.

El valor del atributo class.

Igual que cualquier operaci6n de asignaci611, si el objeto n o es de este tipo, entonces la excepci6n j a v a l a n g .C l a s s C a s t E x c e p t i o n puede ser lanzada en el periodode solicitud.

Capitulo 10
Los procesos subyacentes que tienen lugar son 10s siguientes:
0

El contenedor intenta localizar un objeto que tiene el id especificado dentro del alcance especificado.

0 Si el objeto es encontrado y se ha especificado un tip0 en la etiqueta, el contenedor intenta designar el objeto encontrado a1 tip0 especificado. Si la asignaci6n falla, se lanza una excepci6n ClassCastException. 0 Si el objeto no se encuentra en el alcance especificado y la clase puede ser instanciada, entonces se instancia y una referencia del objeto es asociada con el id otorgado, en el alcance especificado. Si esto falla, se lanzaunaexcepci6n Ins tantiationException. 0 Si el objeto no se encuentra en el alcance especificado y se especifica un beanName, entonces se invoca el mktodo instantiate ( ) de j ava. bean. Beans, con beanName como argumento. Si este mktodo tiene kxito, el nuevo objeto referencia es asociado el id otorgado, en el alcance especificado:
0

Si una nueva instancia bean ha sido instanciada y el elemento < j s p :useBean> tiene un cuerpo no-vacio, el cuerpo es procesado; durante este procesamiento, la nueva variable es inicializada y esti disponible. Los scriptlets o la acci6n estindar < j s p :setproperty> pueden ser utilizados para inicializar la instancia bean, si es necesario.

Los significados de 10s posibles valores del atributo alcance son:


0 El alcance page significa que el objeto es asociado a esta solicitud concreta a esta pigina.

O El alcance request significa que el objeto es asociado a esta solicitud de cliente concreta. Si la solicitud es reenviada a otra JSP utilizando la acci6n < j s p : forward> o si otra JSP es incluida utilizando la acci6n < j s p : include>,el objeto estari disponible.
0 El alcance session significa que el objeto estari disponible durante las solicitudes realizadas por el mismo cliente en la sesi6n actual. 0 El alcanceapplication significa que el objeto estari disponible en cualquier pigina JSP dentro de la misma aplicaci6n Web.

Observe que 10s tres ultimos valores de alcance son 10s mismos que 10s valores disponibles para servlets a1 accedera 10s atributos reques t,session y applicat ion utilizando el API Servlet. El contenedor busca la clase Java que especificamos en la ruta de clase para esa aplicaci6n Web. Si estamos creando un bean de una clase que nosotros mismo hemos escrito, situamos archivo de la clase compilada en el directorio de WEB- INF\classes en nuestra aplicacibn, o en un archivo JAR en el directorio WEBINF\lib. Unavez que hemos examinado < jsp: setproperty> y < j sp: getproperty>, estamos en disposici6n de analizar un ejemplo de c6mo utilizar la acci6n < j s p : useBean>.

La etiqueta estindar< j s p : set Property> es utilizado en combinaci6n con la acci6n< j s p :useBean> descrito en la secci6n precedente, para establecer las propiedades de bean. Las propiedades de bean pueden ser sencillas o indexadas. Los nombres de propiedad se ajustan a las convenciones JavaBean.
Las propiedades de un bean pueden configurarse de las siguientes formas:
0

En el period0 de solicitud a partir de 10s parimetros del objeto solicitud

Fundamentos v arquitectura de JSP


En el periodo de solicitud a partir de una expresi6n evaluada

o A partir de una cadena especificada o refundido en la pigina


A1 establecer propiedades bean a partir del objeto r e q u e s t , la JSP puede elegirse para establecer todas las propiedades en el JavaBean a travks de la acci6n estindar: < j s p : s e t P r o p e r t y name="helpU p r o p e r t y = " * " / > o una unica propiedad que puede ser establecida de forma explicita por una acci6n como la siguiente: < j s p : s e t p r o p e r t y n a m e = " h e l p l ' p r o p e r t y = " w o r d U/> La acci6n < j s p : s e t p r o p e r t y > utiliza el mecanismo de instrospecci6n del bean de Java para descubrir qu6 propiedades estin presentes, sus nombres, si son simples o indexadas, su tip0 y sus mktodos accedente y mutante. Lasintaxis d e l a a c c i b n < j s p : s e t P r o p e r t y > e s : < j s p : s e t p r o p e r t y name="beanName" p r o p e r t y d e t a i l s / > donde p r o p e r t y d e t a i 1s es uno de 10s siguientes:
U property="*"
0

property="propertyName"
property="propertyName"param="parameterName"

U property="propertyName" value="propertyValue"

Observe que p r o p e r t y v a l u e es una cadena o un scriptlet. Los atributos son: Atributo name Descripci6n El nombre de una instancia bean, que ya ha debido ser definido por una etiqueta < j s p : useBean>. Elvalordeesteatributoen< j s p : s e t P r o p e r t y > d e b e s e r e l m i s m o que elvalor delatributoid e n < j s p : u s e B e a n > . El nombre de una propiedad bean cuyo valor esth siendo establecido. la etiqueta busca entre todos 10s parimetros del ob'eto Si el atributo tiene el valor ":'", request e intenta relacionar 10s nombres ti or de arimetro de solicitud con 10s nmbres trpos de propiedad en el bean. ~osvalores lasotcitud sonasignados acadapropiedad en cuyo caso bean coincidente, a menos que un arimetro de solicitud tenga el valor "", , la propiedad bean se mantiene inaeerable.

property

a:

param

Al establecer las propiedades bean a partir de parimetros de solicitud, noes necesario que el bean tenga 10s mismos nombres de propiedad que 10s parimetros de solicitud. elnombre del parametro de solicitudcuyovalor Esteatributoes utilizad~~araespecificar queremos asignar auna ropiedad bean. Si elvalorpar amno esta especificado, se assume qua el pardmetro de soEcitud y la propiedad bean tienen el nimso nombre. Si no hay ningfin parametro de solicitud con este nombre o si tiene el valor"", la accion no tiene efecto sobre el bean.

value

Elvalor a asignar a la propiedad bean. ~ s t e ~ u eser d eun atributo de period0 de solicitud o puede aceptar una expresion como valor. Una etiqueta no puede tener ambos parimetros p a r a m y v a l u e .

Capitulo 10
Cuando las propiedades son asignadas a partir de constantes de cadena o valores de parimetro de solicitud, la conversion se aplica utilizando mCtodos estindar de conversi6n Java; por ejemplo, si una propiedad bean es de t i p o d o u b l e o D o u b l e , se utiliza el mitodo j a v a . l a n g . D o u b l e . v a l u e o f ( S t r i n g ) .Sin embargo, las expresiones del period0 de solicitud pueden ser asignadas a propiedades de cualquier tip0 y el contenedor n o realiza ninguna conversion. Para propiedades indexadas, el valor debe ser un array.

La acci6n< j s p : g e t p r o p e r t y > es complementaria ala acci6n< j s p : s e t P r o p e r t y > y es utilizada para acceder a las propiedades de un bean. Accede a1 valor de una propiedad, la convierte en un string y la imprime en la corriente de salida a1 cliente. Para convertir la propiedad en un string la action:
0 O

Invoca el metodo t o s t r i n g ( ) sobre la propiedad, si es un objeto Convierte el valor directamente en un string, si es una primitiva, utilizando el mCtodo v a l u e o f ( ) de la correspondiente clase envoltorio para el tip0 primitiva

Igual que el comportamiento del m C t o d o s y s t e m . o u t . p r i n t l n ( ) . La sintaxis es la siguiente:

< jsp:getproperty name="name" property="propertyName" />


Y 10s atributos disponibles son:
Atributo name property Descripci6n El i d de la instancia bean desde donde se obtiene la propiedad. El nombre de ropiedad que se debe obtener; Csta es la variable de instancia del bean. Obviamente, g b e m o s crear un bean antes deutilizar < j s p : g e t p r o p e r t y > .

Despuesde habervistolasacciones< j s p : u s e ~ e a n > , < j s p s : e t p r o p e r t y > y <j s p : g e t p r o p e r t y > , construyamos un sencillo ejemplo utilizando las tres. Nuestro ejemplo preguntari a1 usuario su nombre y su lenguaje favorito de programacion y emitird despuCs su veredicto sobre la eleccion. La pigina inicial HTML, b e a n s h t m l , es muy sencilla:

<html> <head> <title>useBean actior> t e s t paqe</title> </head> <body> <hl>useBean a c t i o n t e s t page</hl> <form method="post" action="beans.jspn> < p > P l e a s e e r ~ t e ry o u r u s e r n a m e : < i n p u t t y p e = " t e x t " name="name"> <br>What i s y o u r f a v o r i t e programming < s e l e c t name="lanquage"> <uption value="~Java">Java < o p t i o n value="C++">C+t <option value=" PerlM>Perl </select> </p>

language?

Fundamentos y arquitectura de JSP

Esto envia la solicitud POST a b e a n s . j s p con dos parimetros: name y l a n g u a g e . Esta pigina JSP, b e a n s . j s p , es tambitn muy sencilla:
< j s p : useBean i : i = " l a n g u a g e B e a n " s c o ~ . e = " p a q e " c l a s s = " c o m . w r o x . b e a n s . LanguageBearlW> <j s p : s e t P r o p e r t y n a m e = " l a n g u a g e B e a n " p r o p e r t y = " * " / > </ js p : useBean> <html> <head> <title>useBean action t e s t r e s u l t < / t l t l e > </head> <body> <hl>useBean a c t i o n t e s t result.</hl> <p>Hello, < js p : g e t P r o p e r t y name="lar,guageBeari" p r o p e r t y = " n a m e T ' / > .< / p >

<p>Your f a v o r i t e l a n g u a g e i s < js p : q e t P r o p e r t y name="languageBean" <p>My cornmerits o n y o u r l a n q u a g e : < / p > < p > < ] s p : g e t P r o p e r t y name="languageBean" </p> c/bc?dy> </html>

property="lar~guage"/>. </p>

property="languageComments"/>

Todo el c6digo Java ha sido trasladado a la clase LanguageBean. b e a n s . j s p crea una instancia de LanguageBean con alcance de pigina y utiliza la forma p r o p e r t y = " * " de la acci6n < j s p : s e t P r o p e r t y> para configurar el nombre y las propiedades de lenguaje del bean. Puede utilizar entonces la acci6n < j s p : g e t p r o p e r t y > para recuperar 10s valores de estas propiedades y tambitn la propiedad~an~ua~e~omrnents. Finalmente, la fuente d e ~ a n g u a g e ~ e es an asi:
package public com.wrox. b e a n s ; class LariguageBear~ {

private private public

S t r i n g name; S t r i n g lariguage; L a r ~ g u a ' q e B e a r(i )


{

1
public void this.name
=

s e t N a m e ( S t r i r 1 g name) name;

1
p u b l i c S t r i n g getNamei ) r e t u r r ~ name;

I
public void setlanguage (String language) t h i s . language = language;
{

public

String

getLanguage i )

return l a n g u a g e ;

1
public S t r i n g qetLanguageComments ( ) { iZ ( 1 a n g u a g e . e q u a l s ("Java") ) I r e t u r n "The k i n g of 00 l a n g u a g e s . " ; ] e l c e i f ( l a n g u a g e .e q u a l s 1 4 ' C + + " ) 1 [ r e t u r n " R a t h e r too c o m p l e x f o r s o m e f o l k s ' l i k i n g . " ; I else i f (1anguaqe.equals ("Perl") ) [ r e t u r n "OK i f y o u l i k e i n c o m p r e h e n s i b l e c o d e . "; 1 else { r e t u r n " S o r r y , I ' v e never h e a r d o f " t l a n g u a g e + " . " ;

1 1

I
~ s t es a una sencilla clase bean de Java con un constructor sin argumento, con mktodos s e t y g e t para las propiedadesname y l a n g u a g e y tambiCn el n ~ C t o d o g e t ~ a n ~ u a g e ~ o m m e (n ) t Este s 6ltimo metodo utiliza el valor de la propiedad de lenguaje para emitir algunos comentarios sobre el lenguaje elegido por el usuario (iste es invocado por la acci6n < j s p : g e t p r o p e r t y name=" l a n g u a g e B e a n n praperty="languageCommentsl'/> e n b e a n s . j s p )

G u a r d e b e a n s .h t d y b e a n s .j s p e n eldirectorio ~ S ~ ~ x a m p L le an sg, u a g e B e a n . j a v a en J S P E x a m p l e s \s r c \ c o m \ w r o x \ b e a n s . Compileel bean en%J2EE-HOME%\public-htmIVSPExamples/ WEB-INF/~Ia~sesejecutando el siguiente comando desde el directoriosrc:

Ahora necesitamos crear una aplicaci6n Web. Inicie el servidor J2EE y la herramienta de despliegue. Cree una nueva aplicaci6n y llimela JSPExamples; ahora necesitamos atiadir un componente Web a la aplicaci6n. Hlgalo dirigiendose a F i l e I New I Web Component. . . (Archivo I Nuevo I Componente Web) Ahora necesitamos seleccionar la aplicaci6n a la que el WAR debe ser aiiadida, seleccione JSPExamples. Para el W A R D i s p l a y Name, introduzca JSPExamples. Necesitamos entonces atiadir 10s archivos b e a n s . h t m l , b e a n s . j s p y L a n g u a g e B e a n c l a s s . En la siguiente pantah, elija JSP como tipo de componente. En la siguiente pantah, seleccione J S P F i l e n a m e , b e a n s . j s p y Web Component Name como beans. Seleccione F ~ n i s (Finalizar); h ya estamos preparados para desplegar el componente Web. Vaya a1 men6 Tools (Herramientas) y haga clic en D e p l o y . . (Desplegar) Para c o n t e x t R o o t (Raiz de contesto) introduzca J S P E x a m p l e s y despuis F i n i s h . (Finalizar).

Vaya a http://locaIhost:8000/JSPExamples/beans.html y veri la siguiente pantalla:

Please enter your usemame: l ~ o b e r t What is your favonte programmmg language? IJavaA
Submit information

Ferl

Fundamentos v arauitectura de JSP


Introduzca su nombre y lenguaje y pulse el b o t h S u b m i t i n f o r m a t i o n (Enviar informaci6n):

II II

Hello, Robert. Your favorite language is Java My comments on your language:

The kvlg of 00 larguages.

& I

ist to

r@

A
L O C lntranet ~

La ventaja de este enfoque sobre el utilizado en ejemplos anteriores, en 10s que el codigo Java y HTML eran libremente combinados, debe estar clara. Trasladando la 16gica a la clase L a n g u a g e B e a n , la pigina JSP es mucho legible y, por lo tanto, ficilmente editable por una capacitado disefiador de Web pero que no necesariamente entienda 10s detalles de la programacih Java. Utilizar JavaBeans es solo un modo de evitar cantidades excesivas de c6digo Java en piginas JSP. Otras estrategias incluyen el uso de controladores de servlet y extensiones de etiqueta JSP.

La acci6n < j s p :p a r a d es utilizada para proporcionar otras etiquetas de cierre con informaci6n adicional en forma de pares de valor nombre. Es utilizado en conjunci6n con las acciones < j s p : i n c l u d e > , < j s p : forward> y <j s p : p l u g i n > , y su usoestidescritoenlas siguientes secciones relevantes. La sintaxis es:

Los atributos disponibles son:

Atributo
Name Value

Descripci6n La clave asociada al atributo. (Los atributos con pares de valor clave.) El valor del atributo.

Esta acci6n permite un recurso estitico o dinimico, especificado por un URL, para ser incluido en la actual JSP en el period0 de procesamiento de solicitud. Una pigina incluida s61o tiene acceso al objeto

Capitulo 10
JspWriter y n o puede configurar cabeceras ni cookies. Si se intenta, se lanza una excepci6n de periodo de solicitud. Esta restriccibn es equivalente a la impuesta en el metodo include ( ) de javax .servlet .R e q u e s t D i s p a t c h e r p a r a e s t e tiPo deinclusibn.

Si la informaci6n de salida de la pigina esti buferada, el desarrollador puede elegir si el bdfer debe ser vaciado antes de la inclusibn. La accibn include sufre un pequeho castigo en cuanto a eficacia y la pigina incluida no puede ejecutar todas las operaciones permitidas en piginas JSP de nivel superior. La pigina incluida n o puede intentar modificar las cabeceras de respuesta: esto prohibe operaciones como modificar el tip0 de contenido de la respuesta o establecer cookies. Aunque modificar el tip0 de contenido de la respuesta n o tiene claramente n i n g h sentido en una pigina incluida, la incapacidad para establecer o modificar cookies puede ser en ocasiones problemitica y puede dictar un enfoque alternativo. (Recuerde que 10s cookies son comunicados entre servidor y navegador en cabeceras HTTP.) La sintaxis de laacci6n< j sp: include> es :

< jsp: include page="URLU flush="true" / >

<jsp: include page="URLN flush=" t r u e M > < jsp :param name="paramname" value="paramvalue"

< / jsp: include>

...

/>

Los atributos de la acci6n < j sp : include> son 10s siguientes: Atributo

Descripci6n
El recursoque debe ser incluido. El formatoURLes elmismo que el descritoanteriormente para la directriz include.

flush

Este atributo es optional, conelvalor defectodef alse.Si elvalores true,el blifer de la corriente de salida es vaciado antes de que se realice la inclusion.

H a y una mejora importante en la especifi:caci6n J S P 1.2 con respecto del vaciado. E n J S P 1.1, el tinico valor legal del atributo de vaciado era true.Pernzitir inclusiones i n vaciar el btifer es u n importante avance para JSP 1.2, puesto que una vez que el bufer ha sido vaciado es imposible reenviar a otro recurso dentro de la aplicacidn W e b o utilizar una pdgina de error.

Una acci6n < j sp : include> puede tener uno o mis etiquetas < j sp :param> en su cuerpo, proporcionando pares de valor nombre adicionales. La pigina incluida puede acceder a1 objeto solicitud original, que contendri 10s parimetros originales y 10s nuevos parimetros especificados utilizando la etiqueta < j sp :param>. Si 10s nombres de parimetro son 10s mismos, 10s antiguos valores se mantienen intactos mientras que 10s nuevos valores priman sobre 10s valores existentes. Por ejemplo, si la solicitud tiene un parimetro paraml=myvalue 1 y un parimetro paraml=myvalue2 es especificado en la etiqueta<j sp :param>,la solicitud recibida en la segunda JSP tendri paraml=myvalue2 , myvaluel. Los atributos aumentados pueden ser extraidos de la solicitud (Stringparamname) er enlainterfaz utilizando el m e t o d ~ ~ e t ~ a r a m e t
javax.servlet.Serv1etRequest.

Es importante comprender la diferencia entre la directrzz include y esta accidn include:

Fundamentos v arauitectura de JSP


Tipo Include Sintixis Tiene lugar Contenido incluido Estltico Estitico o dinimico Anilisis

directriz acci6n

<%@include Periodo de f i l e = " f i l e n a m e W % > compilaci6n <jsp:include page="URL" /> Periodo de procesamiento de solicitud

Analizado por el contenedor N o analizado pero incluido en su lugar. El URL especificado es especificado en el periodo de ejecucion como un recurso independiente. El URL incluido puede asociarse a un servlet, en lugar de una JSP.

La directriz i n c l u d e nos permite incluir recursos en mliltiples piginas pero requiere que las piginas a incluir Sean retraducidas si cambia alguno de 10s recursos incluidos. Esto significa que, a menos que nuestro contenedor JSP sea lo suficientemente inteligente para almacenar y comprobar la informaci6n de dependencia en el periodo de procesamiento de solicitud, puede que necesitemos actualizar estiticamente la fecha de modificaci6n en todas las piginas, incluido un fragment0 de pigina modificada, para certificar que son actualizadas. La acci6n i n c l u d e incluye archivos en el periodo de procesamiento de solicitud.
0

Utilice la directriz include si su recurso no va a cambiar con frecuencia

0 Utilice la acci6n include cuando el recurso cambie con frecuencia o sea dinimico

Analicemos un ejemplo. La siguiente JSP, i n c l u d e A c t i o n . j s p , muestra ambos tipos i n c l u d e , para un recurso estitico y un recurso dinimico:
<html> <head> <title>Irlclude Action t e s t page(/title> </head> <body> chl>Include Action t e s t page</hl> ch2>Uslrlg t h e c%@include
<%@ include

include directivec/h2>

%> file="included2.html" f i l e = " i n c l u d e d 2 . js p " % >

'hZ>IJsing

the

include

action</hZ>

'jsp:include 'j s p : i n c l u d e

page="included2.htrnl" flush="true" /> p a g e = " i n c l u d e d 2 . js p " f l u s h = " t r u e W / >

Los dos archivos incluidos son i n c l u d e d 2 . h t m l :


<p>This is some static text in the html file</p>

y i n c l u d e d 2 . j sp:

Capitulo 10
< 4 @ page i m p o r t = " j a v a . u t i l . D a t e w 8 > <%= " C u r r e n t d a t e i s " t new D a t e ( ) %>

Guarde estos archivos en el directorio % J 2 E E ~ A O M E B \ p u b l i c ~ h t m l \ J S P E x a m p l einicie s , el servidor J2EE, solicite entonces http://localhost:8000/JSPExamples/includeAction.jsp; obtendri entonces algo similar a esto:

1 Include Action test ~ a ~ e


m

Using the include directive


Tlus is some static text in the html file
Current date is Tue Aug 14 16:35.06 BST 2001

Using the include action


Tlus is some static text in the html file
Current date rs Tue Aug 14 16:35:12 BST 2001

Hay una pequeiia diferencia entre 10s resultados procedentes de 10s dos tipos de include. Examinemos un extract0 de la clase de servlet generada, un poco ordenada:
//

...
p u b l i c w>i,d - J S F
//

...

p a q e s e r v i c e ( H t t p S e r v l e t K e q u e s t redquest, HttpServletRcsponse response) throws IOException, S e r v l e t E x c o p t i o n 1

# c u t. w r i t e ( " < h t m l > \ r \ n 'head>\r\n < t i t l e > I n c l u d e A c t i o n test p a g e < / t i tie>\ r \ n </head>\r\n <body>\r\n . r h l > I n c l ~ ~ dA ec t i o n t e s t paqe</hl>\r\n\r\n <h2>Usinq t h a i n c l u d e d i r e c t i v e < / h 2 > \ r \ n \ r \ n o u t . w r i t e ( " < h 3 > T h i s is some E t a t i c t e x t i n t h e h t m l f i l e < / h 3 > " ) ; " ; out.write("\r\n < c u t. w r i t e ( " \ r \ r i q ' ) ; o u t . p r i n t ( " C u r r e n t d a t e i s " + new D a t e 0 ) ; out.~::ritelW\r\n\r\n <h2>1Jsing t h e incliude a c t i o n < / h Z > \ r \ r ~ \ r \ r ~

"I;

");

1
String j s p x qStr = " " ; nut.flush0; pageCuntext.include("ir1cluded2.html"

jspx qStr);

1
out . w r i t e ( " \ r \ r ~

"1;

Fundamentos v arquitectura de JSP


String jspx qStr = ""; n u t . f l u s h [ ); p a g e C o r ! t s : < t. i n c l u d e ( " i n c l u d e e j 2 . j s p "

jspx q S t r ) ;

Las lineas resaltadas e n el cddigo anterior muestra c 6 m o el contenedor introduce en-linea 10s recursos para la directriz i n c l u d e y 10s invoca dinirnicarnente para la accidn i n c l u d e . Para reiterar la diferencia, veamos clue ocurre cuando 10s recursos incluidos s o n can~biados, sin cambiar la JSP progenitora que 10s incluye. M o d i f i q u e i n c l u d e d 2 .h t m l d e m o d o que contenga:
<:p>This i s
some

new

t e x t i n the html

file'/p>

y modifique i n c l u d e d 2 . j s p d e rnodo que 10s contenidos sean ahora:


,:p>This
is

the

new JSP</r>

C u a n d o la piginn sea de nuevo solicitada, el result;ldo s e r i el siguiente:

Include Action test page


Using the ii~clude directive
TNs IS some stahc text m the hhnl 6le

Current date 1s Tue Aug 14 17 40 05 BST 2001

Using the include action


TNs
13

some new text m the html 6le

?lus is the new JSP

Las partes incluidas utilizando la directriz i n c l u d e n o son alteradas porquc la JSP progenitora ( i n c l u d e A c t i o n . j s p ) n o ha carnbiado y, por lo tanto, n o es recompilada; sin embargo, las partes incluidas utilizando la accidn i n c l u d e son cambiadas porque la acci6n include realiza la inclusi6n d e nuevo cada vez que la JSP progenitora es solicitada.

Puesto que las estrategias de compilacio'~~ no estkn asigrzahs en la especificncidn JSP, el ~,otnportamiento de este ejernplo prrede ddiferir entre diferentes contenedores JSP. Algunos registrara'n dependencias y recompilara'n autornciticamente la JSP progenitora; / R u n 3.0, por ejenzplo, realiza

Capitulo 10
estas funciones. La mayoria de 10s contenedores no detectara'n el cambio y se comportara'n como en las capturas de pantalla anteriores. Por lo tanto, la ejecucidn de este ejemplo le indicara' si su contenedor J S P requiere o no que no olvide actualizar la fecha en 10s archivos de nivel superior cuando cambien 10s archivos incluidos.

La accidn <I s p : forward> permite que la solicitud sea reenviada a otra JSP, a un servlet o un recurso estitico. Esto resulta particularmente util cuando deseamos dividir la aplicaci6n en diferentes vistas, dependiendo de la solicitud interceptada. C o n anterioridad hemos visto este enfoque de disefio aplicado a servlets y veremos mas sobre i l en este capitulo. La sintaxis es la siguiente:

< j s p : forward

page="URLM

/>

El recurso a1 que la solicitud esti siendo reenviada debe estar en la misma aplicacidn Web que las JSP que esta lanzado la solicitud. La ejecucidn en la actual JSP se detiene cuando encuentra una etiqueta < j s p : forward>. El bufer es limpiado (ista es una redireccidn de lado servidor y el bufer de respuesta es limpiado durante el procesamiento) y la solicitud es modificada para asimilar cualquier parimetro adicional especificado. Estos parametros son asimilados del mismo mod0 descrito para la accidn < j s p : include>. Si la corriente de salida no estuviera buferada y se hubiera escrito en ella alguna informacion de salida, una accidn< j s p : forward>lanzariaunaexcepci6n java. lang. 1 l l e g a l ~ t a t e ~ x c e ~ t i o n . E ~ comportamiento de esta accidn es exactamente igual que el del metodo forward ( ) de javax.servlet.RequestDispatcher. Veamos un sencillo ejemplo de la accidn < j s p : forward> en uso: un simple formulario de registro. El mismo formulario de registro, en forward. html,es direct0 y sencillo, enviando una solicitud POST a forward.j s p :
<htrnl> <head> <title>Forward action test page</title> </head> <body> <hl>Forward action test page</hl> cform method="post" actlon="forward.]spl'> <p>Please enter y ~ u rusername: <input type="textn name="userNamem> <br>and password: < ~ n p u t type="password" name="password">
</p>

forward.jsp es l a prirnera pigirla JSP que h e m s visto que no contiene c5digo HTML:

Fundamentos y arquitectura de JSP

Esta acci6n comprueba si el nornbre de usuario y la contraseiia son aceptables para el sistema y, si es asi, reenvia la solicitud a f orward2. j sp;si el intento de registro falla, utiliza la directriz include para presentar de nuevo el formulario de registro a1 usuario. Finalmente, forward2. j sp presenta a1 usuario registrado una plgina de bienvenida. Puesto que la solicitud original, incluido 10s parimetros de solicitud, ha sido reenviada a esta JSP, podemos utilizar el objeto solicitud para mostrar el nombre de usuario:
ihtml? <head> <ti tle?Forward
</head>

action test:
test:

Lngin

succcssful!</title>

<body'> <hllForward a c t i n n
<p>Walcorne,

Lugir, s u c c e s s f u l < / h l >


,

< % = r e q u e s t . g e t p a r a m e t c r ( " ~ ~ s e r N a mI f : " 2

Guarde todos estos nrchivos en el directorio JSPExamples en el servidor y solicite http:// loca I host :8000/JSPExamples/forward.html:

Archive

3Fawritos a~ult~rnedia ----Direccib ~ h t t p : / f l o c a h s t :8000~3~~xamp1es/~o1 htrnl ward


J=

- -

. -

Edtcth

Ver

Favorites

Herramientas

- 34
-

1 ~a&j54ueda

Ayuda

. J1 @-

ac 3 3 $1,
- -

I Forward action test page


Please enter your username: l ~ i c h a r d and password:

1"

rr!@

local intranet

Introduciendo el nombre de usuario Richard y la contraseiia x y z z y, llegamos a esta pigina:

Capitulo 10

Archivo
- -

Edicidn

--

Ver
-

Favorites
- -

--

Herramientas
--

.-

Ayuda

--

Forward action test: Login - successful


Welcome, &chard

Si se introduce cualquier otro nombre de usuario o contrasefia, el forrnulario de registro es rnostrado de nuevo. Es preferible utilizar un sendet controlador para reenviar una solicitud entrante a la vista adecuada que utilizar un controlador JSP. Recuerde que las plginas JSP son adecuadas para generar contenido per0 n o lo son tanto en el manejo de 16gica de procesamiento.

La acci6n < j s p : p l u g i n > proporciona flcil apoyo para incluir applets d e Java en plginas generadas p o r JSP. Es utilizado para generar etiquetas H T M L especificos d e navegador ( c o bj e c t > o < e n b e d > ) que resultan en la descarga de software Plug-in de Java, si es preciso, seguidos p o r la ejecuci6n del componente applet o JavaBean que es especificado en la etiqueta. (Confia en que JSP detecte nuestro navegador analizando s u string d e agente d e usuario.) Los motivos para utilizar la ncci6n < j s p : p l u g i n > para referenciar applets, en lugar de hacerlo a rnano en datos de plantilla JSP, es que < j s p :p l u g i n > n o s permite olvidarnos p o r una vez de las diferencias d e navegador y el c6digo resultante referencia el Plug-in d e Java, una reciente implementaci6n estindar de Java, mejor que cualquicr VM posiblemente lenta o n o adaptable a Java incorporada a nuestro navegador (si es que es adaptable a Java). La e t i q u e t a c j s p :p l u g i n > tiene dos etiquetas de apoyo opcionales:

a < j s p : p a r a m s > . Para pasar parimetros adicionales a1 componente Applet o JuaBeans.


3

< j s p : f a l l b a c k > . Para especificar el contenido que debe ser mostr;ldo e n el navegador del cliente si el plug-in n o puede ser iniciado porque las etiquetas generados n o son npoyados. La etiqueta < j s p : f a l l b a c k > funciona cotno la etiqueta <noframes>.

La sintaxis de esta acci6n es: < j s p : p l u g i n t y p e = " b e a n I a p p l e t t 1 c o d e = " o b j e c t C o d e W codebase="objectCodebase" align="alignment" archive="archiveListn height="heightM h s p a c e = " h s p a c e W j r e v e r s i o n = " j r e v e r s i o n " name=" componentName" vspace="vspaceM width="width" n s p l u g i n u r l = " u r l " iepluginurl="url" > <j s p : p a r a m s > < j s p : p a r a m name=" paramNameV v a l u e = " p a r a m v a l u e " /> < j s p : p a r a m name=" paramNameU v a l u e = " p a r a m v a l u e " />

... </ j s p : p a r a m s >

<jsp:fallback> Alternate t e x t to display </jsp:fallback> </ j s p : p l u g i n >

Fundamentos y arquitectura de JSP


Los atributos disponibles para la etiquetac j s p : p l u g i n > son: Atributo Detalles Identifica el tip0 del componente: un JavaBean o un Applet code codebase align archive height Igual que la sintixis HTML Igual que la sintixis HTML Igual que la sintixis HTML Igual que la sintixis HTML Igual que la sintixis HTML No, per0 algunos navegadores no permitenun objeto de alturacero debido a temas de seguridad No Requerido

hspace

Igual que la sintixis HTML

jr e v e r s i o n

La version de entorno de period0 de No ejecucibn de Java necesaria ara ejecutar este objeto EI valor por deRcto es l l l . ~ l l . Igual que la sintixis HTML Igual que la sintixis HTML Igual que la sintixis HTML Igual que la sintixis HTML No No No No, per0 algunos navegadores no permiten un objeto de amplitud cero debido a temas de seguridad No

name vspace title width

nspluginurl

URL donde el plug-in de Java puede ser descargado para Netscape Navigator. Valor por defecto definido por la impirmentaci6n.

iepluginurl

URL donde el plug-in de Java puede ser descargado para Netscape Navigator. Valor por defecto definido por la implementacibn.

El siguiente ejemplo muestra la accibn estindar < j s p :p l u g i n > en uso y el HTML generado por el RI para un cliente Internet Explorer 5.5 ejecutado en Windows 2000. Hemos tomado el applet de 10s ejemplos integrados en laversibn JDK 1.3. Para ejecutarlo, tome todo el irbol de muestraMoleculeViewer de JDK, sitfielo en una WARYsitue la siguiente JDK ( a p p l e t .j s p ) en la raiz del d i r e c t o r i o ~ o l e c u l e ~ i e w e r .
<p>This is the molecule viewer example from the JDK 1.3. <p/>

Capitulo 10

C u a n d o esta JSP sea solicitada, el RI generarb el siguiente HTML. Observe que el HTML generado cuida de 10s detalles especificos del sistema operativo como el CLASSID de Windows:

Cunndo solicitamos applet .j sp, debemos ver la siguiente pantalla en nuestro navegador. (Hemos utilizado IE 5.5 per0 lo importance es que la rnisnia JSP funcionari de forma idintica en otros navegadores).

This i s the molecule viewer example From the JDK 1.3.

-,

LLMO.

--

local kt"&

@t

Fundamentos y arquitectura de JSP

Objetos implicitos
El API Senlet incluye interfaces que proporcionan a1 desarrollador abstracciones convenientes, corno ~ t t ~ ~ e r v l e t ~ e ~ u e s t , ~ t t ~ ~ e r v l y~ttp~ervlet~ession.Estasabstracciones et~es~onse encapsulan la irnplernentaci6n del objeto; por ejernplo, l a i n t e r f a z ~ t t ~ s e r v l e t R e q u erepresenta st 10s datos HTTP enviados desde el cliente junto con las cabeceras, 10s parirnetros de forrna, etc. y proporciona rnttodos convenientes corno get Parameter ( ) y getHeader ( ) que extraen datos relevantes de la solicitud. JSP proporciona ciertos objetos irnplicitos, basados en el API Senlet. A estos objetos se accede utilizando variables estindar y estin disponibles para su uso autorniticarnente en nuestra JSP sin tener que escribir ningun codigo extra. Los objetos irnplicitos disponibles en una pigina JSP son 10s siguientes:
O O

request response

O O
0 0

session application out config

El objeto Request
El objeto request representa la solicitud que ha desencadenado la invocaci6n service ( ) . HttpServletRequest proporciona acceso a las cabeceras H T T P entrantes, a1 tipo de solicitud y a 10s pararnetros de solicitud, entre otras cosas. En ttrrninos estrictos, el objeto rnismo seri una subclase de protocolo e irnplernentaci6n de j avax .servlet . ServletRequest pero pocos contenedores JSP (o ninguno) apoyan en la actualidad servlets n o HTTP. Tiene alcance request.

El objeto Response
El objeto response es l a i n s t a n c i a ~ t t p S e r v l e t ~ e s p o n s que e representalarespuestadel senidorala solicitud. Es legal establecer 10s c6digos de estado y cabeceras HTTP en la pigina JSP una vez que la inforrnaci6n de salida ha sido enviada el cliente (aunque no esta perrnitido en senlets, puesto que las corrientes de salida JSP estin buferizadas por defecto). De nuevo, el objeto seri, en ttrrninos estrlctos, una subclase especificadeprotocolo e irnplernentacion de j avax .servlet .ServletResponse.Tienealcancepage.

El objeto Pagecontext
El objeto pagecontext proporciona un h i c o punto de acceso a muchos de 10s atributos de pigina y es un lugar conveniente para situar datos cornpartidos en la pigina. Es de tip0 j avax .servlet . j sp. ~ a ~ e ~ o n t e n t y t i e n e a k a n c e p a g e .

El objeto Session
El objeto s e s s i o n representa la sesi6n creada para el objeto solicitante. Las sesiones son creadas autorniticarnente y una nueva sesi6n esti disponible incluso cuando no hay sesi6n entrante (a rnenos, por

supuesto, que hay utilizado el atributo s e s s i o n = " f a l s e " en la directriz de la pigina, en cuyo caso esta variable no estaridisponible). El objeto session es de tip0 j a v a x . s e r v l e t . h t t p . H t t p S e s s i o n y tienealcancesession.

A menudo es conveniente marcar nuestras piginas indicando que no requieren una sesion. Para aplicaciones simples o sin estado, esto maximizari el nivel de reajustabilidad certificando que nuestra aplicaci6n puede ser ejecutada en un cluster de sewidores sin la sobrecarga de replicaci6n de estado-sesi6n entre las miquinas del cluster. Sin embargo, una aplicacidn que requiere mucho estado de sesi6n sin utilizar u n a H t t p S e s s i o n , sera dificil de mantener.

El objeto Application
El objeto a p p l i c a t i o n representa el contexto de servlet, obtenido a partir del objeto de configuration de sewlet. Es de tipo j a v a x . s e r v l e t .S e r v l e t c o n t e x t y tienealcanceapplication.

El objeto Out
El objeto o u t es el objeto que escribe en la corriente de salida a1 cliente. Para hacer que el objeto response sea util, Csta es una versi6n bufferada de la clase j a v a . i o .P r i n t w r i t e r y es de tipo j a v a x .s e r v l e t . j s p . J s p W r i t e r . el tamafio del bufer puede ser ajustado mediante el atributo bufer en la directrizpage.

El objeto Config
El objeto c o n f i g es el s e r v l e t c o n f i g para esta pigina JSP y tiene alcance page. Es de tipo javax.servlet.ServletConfig.

El objeto Page
El objeto p a g e es la instancia de la clase de servlet de la implementaci6n de la pigina que esti procesando la solicitud actual. Es de tip0 j a v a l a n g ~b j e c t y tiene alcance page. El objeto page puede concebirse como un sin6nimo de t h i s dentro de la pigina.

El alcance de 10s objetos JSP (JavaBeans y objetos implicitos) es fundamental puesto que define cuinto tiempo y desde qu6 piginas JSP estari disponible el objeto. Por ejemplo, el objeto s e s s i o n tiene un alcance que supera una tinica pigina ya que puede producir varias solicitudes de cliente y piginas. El objeto a p p l i c a t i o n puede proporcionar servicios a un grupo de piginas JSP que representan juntas la aplicaci6n Web. Los alcances JSP confian internamente en contextos. U n contexto proporciona un contenedor invisible para recursos y una interfaz para que se comuniquen con el entorno; por ejemplo, un servlet se ejecuta en un contexto (una instancia de s e r v l e t c o n t e x t , en realidad). Todo lo que el sewlet necesita para l . 2 conocer a su servidor puede ser extraido de este contexto y todo lo que el sewidor quiere comunicar el -1 sewlet pasa por el contexto.

Una buena regla prictica es que todo en JSP esti asociado a un contexto y todo contexto tiene un alcance. Mis adelante veremos quC sucede cuando una etiqueta bean es compilado para diferentes valores de alcance (scope).

Fundamentos v arauitectura de JSP


Alcance de pagina
U n objeto con alcance depiginaesti asociado a j a v a x . s e r v l e t . j s p . P a g e c o n t e x t . Es relativamente sencillo: significa que el objeto es situado en el objeto P a g e c o n t e x t durante el tiempo que esta pigina estC respondiendo a la solicitud actual. A un objeto con este alcance se puede acceder invocando 10s metodos g e t A t t r i b u t e ( ) sobre el objeto P a g e c o n t e x t . La referencia de objeto es descartada en la conclusidn de la invocaci6n del actual metodo ~ e r v l e.ts e r v i c e ( ) (en otras palabras, cuando la pigina es procesada por completo por 10s servlets generados a partir de JSP). A1 generar el servlet, la miquina servlet crea un objeto en el metodo s e r v i c e ( ) , que sigue la habitual convencion de alcance de objeto en Java. Este objeto es creado y destruido para cada solicitud de cliente a la pigina. ~ s t es e el alcance por defect0 para objetos utilizados con la acci6n < j s p : u s e B e a n > .

Alcance de solicitud
Elalcance de solicitudsignificaque el objeto esti asociado a j a v a x . s e r v l e t .s e r v l e t ~ e q u e sy t que se puede acceder a 61 invocando 10s metodos g e t A t t r i b u t e ( ) sobre el objeto implicito r e q u e s t .

La referencia de objeto esti disponible mientras que el o b j e t o ~ t t ~ ~ et~ existe, u e s incluso si la solicitud es reenviada a diferentes piginas, o si se utiliza la acci6n < j s p :i n c l u d e > . El servlet generado subyacente confia enasociare~objetoa~tt~~ervlet~equestuti~izandoe~m~todoset~ttribute (Stringkey, Object v a l u e ) e n H t t p S e r v l e t R e q u e s t ; Cste es transparente para el autor de JSP. El objeto es distinto para cada solicitud de cliente (en otras palabras, es creado de nuevo y destruido para cada nueva solicitud).

Alcance de sesion
U n objeto con alcance de sesi6n estiasociado a j a v a x . s e r v l e t . j s p . P a g e c o n t e x t y sepuede acceder a 61 invocando 10s metodos g e t v a l u e ( ) sobre el objeto implicito de sesi6n. El servlet generado confia en asociar el objeto a H t t p s : s s i o n utilizando el metodo s e t A t t r i b u t e ( S t r i n g k e y , O b j e c t v a l u e ) . Este es tambikn transparente para el autor de JSP: el objeto es distinto para cada cliente y esti disponible mientras la sesi6n del cliente seavilida.

Alcance de aplicacion
Elalcance de aplicaci6nsignificaqueelobjeto estiasociado a j a v a x . s e r v l e t . S e r v l e t c o n t e x t . Se puede acceder a un objeto con este alcance invocando 10s mCtodos g e t A t t r i b u t e ( ) sobre el objeto implicitoapplication. ~ s t es e el alcance mis persistente. El servlet generado confia en asocia el objeto a s e r v l e t c o n t e x t utilizandoelmCtodoset~ttribute ( s t r i n g key, Object v a l u e ) enServletContext.Noes exclusivo de clientes individuales y consecuentemente, todos 10s clientes acceden a1 mismo objeto, puesto que todos acceden a1 rnisrno s e r v l e t c o n t e x t . Al acceder a las variables de aplicaci6n, aseglirese de que su c6digo esti a salvo de hilos. Las variables de apkaci6n estin a menudo pobladas en el arranque de la aplicaci6n y despues son de s61o lectura.

Paginas JSP como documentos XML


La especificaci6n 1.1 de JSP introduce una sintaxis alternativa basada en XML para pigina JSP que sustituye a 10s elernentos de directrices y directivas por alternativas adaptadas a XML. La especificacih 1.2

507

Capitulo 10
de JSP da un paso rnis en esta posibilidad precisando rniquinas JSP para aceptar piginas JSP corno docurnentos XML y basando el nuevo rnecanisrno de validaci6n de bibliotecas de etiquetas en la representacibn de piginas JSP. La sintaxis XML no esta destinada a la cornposicibn manual de piginas JSP, por lo que nunca reernplazari la sintaxis JSP que hernos analizado hasta el rnomento. Sin embargo, una sintaxis basada en XML puede ser preferible cuando las piginas JSP son elaboradas por rniquinas y facilita la rnanipulaci6n de las piginas. Una de las razones por las que representar piginas JSP corno docurnentos XML facilita la cornposici6n con rniquina y la rnanipulaci6n de piginas es la capacidad y conveniencia de XSLT, el lenguaje de hoja de estilo para transforrnaciones XML. Las hojas de estilo XSLT pueden utilizarse ficilrnente para transformar docurnentos JSP XML en casi cualquier forrna requerida. Observe tarnbih que es dificil generar docurnentos en la sintaxis JSP habitual utilizando XSLT. Una hoja de estilo XSLT es en si rnisrna un docurnento XML y constructores JSP corno < %no estin perrnitidos en docurnentos XML. Las piginas JSP en forma XML puede ser validadas utilizando el D T D o la definici6n XML Schema provista en la especificaci6n JSP 1.2. El D T D resulta rnis legible pero la definici6n de esquerna es preferida corno norrna de validaci6n. Los siguientes ejernplos ilustran la sintaxis de equivalentes XML de 10s constructores JSP que hernos visto hasta el rnornento.

Directrices
Para una directriz de la forrna:
< % @directiveName

ATTRIBUTES

%>

la sintaxis equivalente de base XML es: < jsp:directive.directiveName ATTRIBUTES /> La excepci6n es la directriz taglib, que es representada por un atributo xmlns : dentro el elernento raiz de la pigina JSP. La correspondencia natural entre prefijos de libreria de etiquetas y nornbres de espacio XML ilustra 10s esfuerzos de Sun para que JSP se acerque rnis a XML, incluso si la sintaxis regular nunca puede curnplir con XML.

Elementos de directivas
Una declaraci6n JSP de la forrna:
< % ! declaration

code %>

es reresentada en XL corno:
<jsp:declaration> declaration code </jsp:declaration>

U n scriptlet de la forrna:
<% scriptlet code %>

es representado por:
<jsp:scriptlet> scriptlet code </jsp:scriptlet>

Finalrnente, una expresion de la forrna:


<%= expression

code %>

es representada por:

Fundamentos v arquitectura de JSP


<jsp:expression> expression c o d e </jsp:expression>

Acciones
La sintaxis de acciones JSP ya esti basada en XML. Los hnicos cambios necesarios son debidos a convenciones de citado y a la sintaxis de cualquier atributo de period0 de solicitud.

Una pagina de ejemplo


El siguiente ejemplo de una sencilla pigina JSP en forma normal y XML es tomado de la especificaci6n JSP 1.2. Observe que la forma XML es mis extensa y no es ficil de componer de forma manual, dada la necesidad de librarse de contenido de scriptlet de elementos CDATA. (Esto es necesario porque algunos caracteres utilizados en lenguaje Java como < no son legales en XML sin eliminar.)
Sintaxis JSP
<html> <head> <title>positiveTagLib</title> </head> <body> < % @ taglib uri="http://java.apache.org/tomcat/exarnples-taglib" prefix="egW % > < % @ taglib uri="/torncat/taglib" prefix="testM % > < % @ taglib uri="WEB-INF/tlds/rny.tld" prefix="ternpM % > <eg:test toBrowser="trueW attl="Working"> Positive Test taglib directive </eg:test> </body> </htrnl>

< j s p : root xrnlns: jsp="http://j ava.sur1.corn/jsp 1 2" xrnlr~s:eg="http://java.apache.org/torncat/exarnples-taglib" xrnlns: t e s t = " u r n : j sptld:/tomcat/taglibb' xrnlns: ternp="urn: j s p t l d : /WEB-INF/tlds/rny. t1d1'> <jsp:cdata><! [CDATA[<htrnl> <head> <title>positiveTagLig</title> </head> <body> I I > < / j sp: cdata> <eg:test toBrowser="true" attl="Working> <jsp:cdata>Positive test taglib directive</jsp:cdata> </eg:test> <jsp:cdata><! [CDATA[ </body> </htrnl> ] ] ></jsp:cdata> < / jsp:root>

Apoyo tecnico JSP


Ahora que ya esti familiarizado con la funcionalidad central de JSP, volvamos a nuestra aplicaci6n de Apoyo Tkcnico y convirtimosla en una aplicaci6n de base JSP. La aplicaci6n modificada ilustrari el uso de directrices, acciones estindar, scriptlets y JavaBeans de sesi6n.

La aplicaci6n funcionarj. del misrno rnodo que anteriormente. El usuario va a la pigina de bienvenida e introduce entonces una direcci6n de e-mail y detalles del problema tkcnico:

Technical Support Request

Operacylg System

Problem Description
Randomly reboots Ylndoua

Al hacer clic e n S u b m i t Request, la aplicaci6n comprueba si el usuario es conocido para el sisterna (basindose en la direcci6n de e-mail) y, si n o lo es, reenvia la solicitud a la pigina de registro del cliente:

Please register
First Name: Last Name:
l~obert

Shaw

Phone Number. 123-456-7090

Una vez han sido introducidos estos detalles, se muestra una pigina d e confirmaci6n.

510

Fundamentos y arquitectura de JSP


(Si la direccidn de e-mail del usuario ya esti registrada, el usuario es llevado directamente a la pigina y n o al formulario de registro.)

Diseno de aplicacion
La amplia estructura de la aplicacidn es aproximadamente igual a la anterior, except0 en que las piginas JSP reemplazan a 10s servlets y la 16gica es trasladada a un J a v a B e a n :

'nC'ulr
SI

banner jsp

esta reglstrado

POST

I
TechSupport.jsp reenvlar usos
; I

techsupp html

no e s t i reglstrado

reenvlar

'

I -+
4

I
r e s t e r jsp usos

--!c
Usos b

TechSupportBean (asoc~ado a seslon)

T e c h S u p p o r t S e r v l e t ha sido reemplazado por t e c h s u p p o r t . j s p , r e g i s t e r . h t m l por regform.jsp,RegisterCustomerServletpor register.jsp,ResponseServletpor response.jspyBannerServ1etporbanner.jsp. T e c h S u p p o r t B e a n proporciona a nuestro "modelo" la 16gica de aplicacidn y es utilizada a lo largo del proceso de una consulta de apoyo: se crea una instancia en techsupport y se asocia a la sesibn y entonces es reutilizada en otras piginas JSP de la aplicacidn. El archivo JDBCHelper . j a v a encapsula el cddigo necesario para el acceso a la base de datos. A medida que se va recabando la informacibn, se almacena en las propiedades del bean. Cuando nuestro usuario llega a r e s p o n s e .j s p , el bean ya contiene todos 10s datos sobre la solicitud de auovo. iunto con 10s detalles del usuario obtenidos a oartir de una entrada de la base , ,, de datos existentes o a partir de 10s detalles proporcionados en el formulario de registro. Puede ser entonces utilizada para formular la respuesta a1 usuario.
1

La pagina de bienvenida
t e c h s u p p .h t m l es el formulario de entrada a1 sistema y es pricticamente el mismo de la versibn del capitulo 7. La 6nica diferencia es que ahora utilizamos el metodo POST y enviamos la solicitud desde el f o r m u l a r i o a t e c h S u p p o r t js p :

<html> < ! - techsupp. html > <head> <title>XYZ Corporation, IT Department</tltle>


</head>

Capitulo 10
<body> <hl>Technical Support Request</hl> <hr><br> <center> JSPTechSupport/techSupport. j sp" mett~od="EOST"> <form actior,="/ <table aligr~="center" widtt1="100%" cellspacing="2" cellpaddit~,a="2",, <tri<td allqn="riqhtn\Email : c/td> <td><ir~put type="text" r,ame="email" aliqn="left" size="Z5",//td,</tr> ' t r \ . t d aliqn="riqht"iSoftware:</td., <td><select name="softwareW si=e="l"\ <option value="Word">Micr~soft Word</option> /owtion value="Excel">Microsoft Excel</optiorti cow ti or^ value="Access">Microsoft Access'/owtio~-1' </selecti</td\ <trS aliilt~l="riqht">Operatir1q System:</td> <td><select riarne="os" size="l"> ioptior, value="95"iWir~dows 95</option> <(:ption value="9e"iWirdows 98</option> <option value="NT"~Wirdows NT</option> //select></td></tr> </tat,le>

Esta pigina es designada c o m o el archivo de bienvenida de la aplicacion en Web. x m l :

< ! DOCTY PE Web-app


PIJBLIP

"-//Sun Microsystems, 11~ic. //DTD Web Applicatioil "tlttp:/ / j ava. sun. com/,3td/Web-app 2. 3.sAt'J"'
-

2. 3//EtJ1'

<Web-app' <displa y - ~ n a m e > J S P T e c h S u p p o r t < / d i s p l a \ i - - r ~ a r r ~ e > 'welcome-file-list\ <welcome-file'techsupp.html</welcorne-file> </welcome-file-list\ <resource-ref' <res-ref - n a r r ~ e i j d b c / t e c h S ~ u p p o r t D B < / r e s - r e f - n a m e > <res-type>j avax. sql. IataS'iurce</res-type> <res-auth>Container</res-autth' </resource-ref> /Web-app,

La pagina JSP de procesamiento de solicitudes


Cuando el usuario envia una solicitud de apoyo tkcnico, la informacidn de su navegador es enviada a t e c h s u p p o r t j sp. Esta pigina n o contiene detalles de presentation; crea una instancia de T e c h s u p p o r t b e a n asociada a la sesibn (si todavia noexiste una) utiliza la accion < j s p : s e t p r o p e r t y > para configurar el e-mail del bean, el software, el sistema operativo y las propiedades del problema en 10s valores enviados por el usuario. Fijese en la especificaci6n de una pigina de error e n una directriz de pigina; si esta pigina encuentra una exception, e r r o r . j s p seri invocado y tendri acceso a la excepci6n responsable:

Fundamentos v arauitectura de JSP

< % @p a g e

errorPage="/errur.jspn

%>

<jsp:useBean id="techSupportBeann scope="session" c l a s s = " c o r n . w ~ - o xt. e c h s u p p o ~ . ~ Tt e c h S u p p o r t B e a / \ < j s p : s e t P r o p e r t y name="techSupportBean" p r o p e r t y = " * " / >

Utiliza entonces un scriptlet para invocar el metodo regis terSupportReques t ( ) del bean, que almacena 10s detalles de la solicitud de apoyo en la tabla SUP-REQUESTS de la base de datos y comprueba la tabla CUSTOMERS para ver si esta direccibn de e-mail ya esti registrada:

Finalrnente, utilizamos el metodo isRegistered ( ) del bean para recuperar 10s detalles que indican si el usuario ha sido o no reconocido y reenvia la solicitud directamente a response. j sp,o a
regf orm. j sp:
c% if <%

( t e c h S u p p o r t B e a r ~i. s R e g i s t e r e W [ < j s p : f o r w a r d p a g e = " ~ e s p a n s ej. s p " / \ e l s e { %> < j s p : forward page="regEurm. j s p W / >
%>

%>

<% }

La clase JDBCHelper
~ s t es a una clase visible para el paquete utilizada para obtener una conexi6n y limpieza del acceso de JDBC.
package com.wros.techsupport;

import java. s q l . + ; i m p o r t j a v a x . s q l . +; i m ~ ' o r t j a v a x . naming . + ; class JDBCHelpe-r

//jrldiPlarne e s e l norrbre JNDI de l a fuerite de ciatos a u t i l i z a r para obtener uria conezitr,. p r l v a t e S t r i n g jndiName = "techSupportUB";

/ / C r e a r un n u e v o JDBCHelper p u b l i c J D B C H e l p e r ( S t r i r ~ gj n d i N a m e ) t h i s . j ndiName = j ndiName;


// //

@ p a r a m j n d i r l a m e nombre JNDI d e l a f u e r j t e ,de d a t o s a u t i l i z a r o b t e r ~ e r una c o n e x i h n C o n n e c t i o n g e t c o n n e c t i o n ( ) t h r a w s Namir~gEsception, SQLException Context initCtx = r,ull; try i / / O b t e n e r e l c o n t e x t o JNDI i n i c i a l i n i t C t x = new I n i t i a l C o n t e s t ( ) ;

para
{

/ / Realizar bfisyuda J N D I para obtener f a c t o r i a de conezihr~ de gestor de recursos


Datasource d s = (javax.sql.DataSource) i r ~ i t c t x l.o o k u p ( " j a v a : c o m p / e n v / j d b c / "
t

jndiName1 ;

/ / Invocar f a c t o r i a para obterler return ds.getConnectiori();


1

urla

conexibr,.

Capitulo 10
finally { / / No o l v i d e c e r r a r e l i f ( i n i t c t x != n u l l ) [ initCtx.close();

el

contexto de

riombrado

t
I
/ / L i m p i e s i e m p r e , i n c l u s o s i e n c u e n t r a una e x c e p c i h n SQL v o i d c l e a r ~ u pC ( onnection databa~eCor~r~ectiori, Statement statementl, S t a r e m e n t s t a t e m e n t 2 ) throws SQLException 1 try i / / C i e r r e l a conexibn de base de d a t o s e i n s t r u c c i b n i f (statement1 !- n u l l ) { statementl. close ( ) ;

1
if (statement2 != n u l l ) statement2.closei);
{

!
finally { / / A s e g l i r e s e d e q u e s i e r n p r e i n t e n t a m o s c e r r a r l a conexi6r1, / / s i a l g o f a 1 1 6 a 1 i n t e n t a r c e r r a r una i n s t r u c c i h n i f (databaseConnection != n u l l ) { databaseConnection. close ( ) ; incluso

TechsupportBean
Entonces, ic6mo r e a h a ~ e c h ~ u p p o r t ~ todo e a n este trabajo para techsupport jsp? Empecemos por la parte ficil: la$laraci6n de clase, variables de miembro y 10s mitodos para obtener y configurar propiedades:
//
TechSupportBean com.wrox.techsupport;
j ava. s q l .

package import public

*;
[

class

TechSupportBean

/ / nombre J N D I d e l a private static final


private private private private private private private private private public String String String String String String String boolean

f u e n t e d e d a t o s que r e q u i e r e e s t a c l a s e A M E = "techSupportDB"; S t r i n g DATA SOURCE N

email; software; 0s; problem; firstName; 1astName; phoneNumber; registered; jdbcHe1pe-i;


{

JDBCHeiper

TechSupportBean ( )

Fundamentos y arquitectura de JSP


jdbcHelper
1
=

n e w JDBCHelper(DATA SOURCE NAME);

public void setEmail(String email) [ this.emai1 = email;


1

// //

. . . y similar para el software, problema os y propiedades d e nombre, apellido y nfimero d e telefono

public String g e t E m a i l 0 return email;

1
// // //

.. . y similar para el software, problema os y propiedades d e nombre, apellido y ndmero d e telefono

. ..

mas propiedades y metodos

. ..

I
En una aplicaci6n de calidad de producci6n, el nombre de clase del driver y el URL JDBC podria ser leido desde 10s parimetros de context0 del descriptor de despliegue. (E incluso podriamos utilizar una reserva de conexi6n de base de datos gestionada por la miquina de servlet o acceder a la base de datos s61o a travks de una capa de EJB.) Tambikn hemos provisto mktodos para configurar y obtener diversas propiedades que todavia no hemos tratado: nombre, apellido y nGmero de telkfono. Estos detalles serin recuperados de la base de datos (si el usuario ya esti registrado) u obtenidos en un momento del formulario de registro. Recuerde que este bean seri utilizado durante la sesi6n del usuario, n o s610 a partir de techsupport. j sp. El verdadero trabajo tiene lugar en el mktodo registersupport ( ) y el verdadero c6digo es muy similar a1 del capitulo 7. Reutilizamos la clase sequencer con algunos cambios, como veremos en breve. (Esto genera 10s nGmeros exclusivos de solicitud de apoyo de la tabla SEQ-NO.) La principal diferencia ( ) no reenvia en realidad la solicitud; simplemente estriba en que el mktodo registersupport ~ e q u e s estableceana propiedad boolean, registered, que es true si el usuario esti registrado y a la que se puede acceder desde el JSP de control. Si el usuario esti registrado, establecemos adicionalmente las propiedades firs tName (nombre), 1 as tName (apellido) y phoneNumbe r (nGmero de telkfono), de mod0 que se pueda acceder a ellas posteriormente desde otras piginas JSP:
publlc void
registerSupportRequest() throws SQLException, javax.naming.NamingException [ int requestId = 0; Connection connection = null; String irisertstatementstr = "INSERT INTO SUPP REQUESTS VALUES(?, ?, ?, ?, ? ) " ; String selectCustomerStr = "SELECT CUSTOMERS.FNAME, CUSTOMERS.LNAME FROM CUSTOMERS " + "WHERE CUSTOMERS.EMAIL = ? " ;

Preparedstatement insertstatement PreparedStatement selectstatement try { connection

= =

null; null;
) ;

jdbcHe1per.getConnection (

insertStatement.setInt(1, requestId); insertStatement.setString(2, email);

Capitulo 10
insertStatement. setstring (3, software); insertStatement .setStrir~q ( 4 , 0s); i n s e r t S t a t e m e n t . s e t S t r i n q (5, problem) ;

//

V e r i f i q u e a h o r a s i e l u s u a r i o e s t i o no r e q i s t r a d o . s e l e c t S t a t e m e n t = c o n n e c t i o n . p r e p a r e S t a t e m e n t ( s e l e c t C u s t o m e r S t r ); s e l e c t S t a t e m e n t . s e t S t r i n q (1, e m a i l 1 ;

i f

(rs.hext0) { s e t F i r s t N a m e (rs.qetStrirlq("FNAMEE') ); s e t L a s t N a m e ( r s . q e t S t r i r , q ("LNAME") ) ; s e t P h o n e N u m b e r ( r s . q e t . S t r i n q ("PHONE") ) ;

/ / El usuario ha sido reqistrado / / p6gina d e r e s p u e s t a

podemos

i r directamente

la

registered = true; else ( \ reqistered = false;

I
r s .close ( ) ;

I
finally [ jdbcHelper. cleanup (cc?nnection, selectstatement, i n s e r t S t a t e m e r l t );

Esto es todo por el momento en cuanto a TechSupportBean per0 seri necesario que pronto regresemos y aiiadamos un metodo mas.

Formulario de registro
Si el usuario no esti registrado, es reenviado a regform. j sp, donde se muestra un formulario de registro. En esta versi6n de la aplicacibn, esta pigina es simplemente una pigina JSP por lo que puede reenviarse una solicitud POST, aunque podriamos por supuesto ahadir mis personalizaci6n a1 formulario utilizando 10s detalles introducidos hasta el momento. El c6digo es muy sencillo y una vez mis es muy similar a la pigina correspondiente de la versi6n der servlet de la aplicaci6n:
<

<html\ ! regform. j s p > <head> <title>Customer Reqistration</title..</head> <body> <center><hl>Customer R e q i s t r a t i o r ~ < / h l > < / c e r ~ t e r > <hr> Please register. method="POST"> < f o r m actior~="/JSPTechSuppc?rt/reqister.js~" ..:table> < t r > < t d i F i r s t Name: < / t d > < t d > < i n p u t t y p e = " t e x t l ' narne="firstName" s i z e = " 3 0 " > < / t d > < / t r > < t r > < t d > L a s t Name:</td> < t d > < i n p u t t y p e = " t e x t n name="lastNameW s i z e = " 3 0 " > < / t d \ < / t r > < t r > < t d > P h o n e Number: < / t d > < t d > < i n p u t t y p e = " t e x t l ' name="phoneNurnber" s i z e = " 3 0 " > < / t d > < / t r >

Fundamentos y arquitectura de JSP

C o n 10s detalles introducidos, el usuario puede enviar el formulario a r e g i s t e r . j s p .

JSP de registro
< % register. j s p - % >
/#@

page

e r r o r P a g e = " / e r r o ~ jsp" .

%>

cj s p : useBean id="techSupportBean" scope="session" class="com.wrox.techsupport.TechSupportBear~" / > <j sp: setproperty name="techSupportBean" property="*"/>

<j s p : fol-ward paqe="response. j sp"/>

Recuerda mucho a t e c h s u p p o r t . j s J p e r o es incluso mis sencillo. Necesitamos configurar las propiedades fi r s t N a m e , l a s t N a m e y phoneNumber del bean a partir de 10s detalles provistos en el formulario e invocar el metodo r e g i s t e r c u s t o m e r ( ) para introducir estos detalles en la base de datos. Afiada el siguiente c6digo a1 final d e ~ e c h ~ u ~ ~ o r t ~ve ja a :a n .
//

En TechSupportBean. j ava registercustomer


( )

public void

throws

SQLException, javax. naminq.NamingException

Conr,ection connection = null; Preparedstatement insertStatement = null; String insertStatementStr = "INSERT INTO CUSTOMERS VALUES(?, ?, try I connection = j d b c H e l p e r . g e t C o n n e c t i o r ~( ) ;

?,

?)";

insert St at ement = connection.prepareStatement (insertStatementStr); insertStatement .setstring ( 1 , email) ; insertstatement. setStrir13(2, firstName) ; insertStatement.setStrinq(3, lastName); i n s e r t S t a t e m e n t . s e t S t r i n q ( 4 , phoneNumber); insertStatement.executeUpdate();

I
finally { jdbcHelper. cleanup (cor1r1ectior~, insertstatement, n u l l );

Finalmente, la solicitud es reenviada a r e s p o n s e . j s p .

Las paginas JSP de respuesta y de anuncio


En este momento, aunque el usuario n o esti registrado, la solicitud habri sido reenviada a r e s p o n s e . j s p y las propiedades d e ~ e c h ~ u ~ ~ o r t ~ e a n e s pobladas t a r d n por completo con detalles del

Capitulo 10
usuario y su solicitud de apoyo. r e s p o n s e . j s p imprime un sencillo mensaje, utilizando un include estitico para incorporar el pie de la pigina, b a n n e r . j s p :
<%-

response. j sp - % >

errorPage="/error. jsp" % > <html> <head><title>Customer Service Response</title></head> <body> <hl>Customer Service Request Received</hl>
< % @ page

<p>Thank you for your request, which has been recorded and will be responded to within three business days.</p>
< % @ include

file="/banner. jsp" % >

b a n n e r . j s p simplemente accede al bean una vez mis para extraer e imprimir el nombre del usuario:
<%-

banner. jsp - % >

<hr> Current User: <jsp:getProperty name="techSupportBean" property="firstNamen / > <jsp:getProperty r ~ a m e = " t e c h S u p p o r t B e a r ~ "property="lastNamen / > <hr> XYZ Corporation, Customer Service at 1.800.xyz.corp.<br>

Observe que es mucho mis conveniente generar las insignias utilizando JSP en lugar de servlets.

La pagina de error
Finalmente, proporcionamos una sencilla pigina de error, e r r o r . j s p , que es referenciada por todas las piginas JSP que pueden fallar durante el procesamiento:
< % - error. j s p -%>
< % @ page

isErrorPage="trueM % >

<p>Wefre sorry, an error occurred processing your request.</p> <p>You got a < % = exception % >

Fundamentos y arquitectura de JSP

Desplegar la aplicacion
Solo queda asegurar que 10s archivos necesarios se encuentran en 10s directorios correctos, que las clases Java estin compiladas:
O
O

Las piginas JSP y HTML estin situadas en el directorio J S P T e c h S u p p o r t . Sit6eweb. xml, como siempre, en el directorio J S P T ~ C ~ S U ~ ~ O ~ ~ / W E BAsi -INF. aseguraremos que tenemos una aplicacion Web vilida que puede ser desplegada en cualquier contenedor. El archivo fuente de J a v a T e c h s u p p o r t B e a n se situa enJS P T e c h S u p p o r t / s r c . Compile el archivo fuente de Javaenel d i r e c t o r i o J ~ ~ ~ e c h ~ u p p o r t / ~ ~ ~ - I N F / c l a s s e s ejecutando el comando:

O O

del directorios r c .
O

Ahora necesitamos crear un archivo WAR para la aplicaci6n. Introduzca el siguiente comando en la carpetaJSPTechSupport:
jar -cvf JSPtechSupport.war

*. *

Ahora necesitamos iniciar el servidor J2EE y la herramienta de despliegue de la aplicacibn.


O

Cree u n a n u e v a a p l i c a c i 6 n ~ ~ ~ ~ e c h ~ eu a~ r ~aiiadael o r t . archivo J S P T e c h S u p p o r t . w a r como un nuevo fichero Web. Seleccione ahora la aplicaci6n y haga clic en la etiqueta Resource Refs. Ahora necesitamos una nueva referencia de recurso. Introduzca 10s siguientes valores para la referencia: Coded Name: j d b c / t e c h s u p p o r t ~ B Type: j a v a x . s q l . D a t a s o u r c e Authentication: c o n t a i n e r Sharable: Mantener marcado (por defecto) \ JNDI Name: j d b c / T e c h S u p p o r t

Despliegue ahora la aplicacion, introduciendo J S P T e c h S u p p o r t para el contexto. Inicie la base de datos Cloudscape y reinicie el servidor J2EE. Finalmente, podemos navegar hasta http://localhost:800O/JSPTechSupport.

O O

Entonces, ic6mo nos ha ido a1 convertir la aplicacion de Apoyo Tecnico en JSP? El uso de un JavaBean para encapsular el acceso a la base de datos y la 16gica de aplicacidn nos ha evitado muchas de las trampas en las que podiamos haber caido. Las piginas JSP de dividen claramente en dos grupos:
0 Las que proporcionan control de flujo y actualizan el modelo de aplicaci6n, t e c h s u p p o r t . j s p y

r e g i s t e r . j s p , que no contienen anotaci6n HTML y no crean respuestas por si mismas.


O

Las paginas compuestas en su mayor parte por HTML, con etiquetas de expresi6n y accidn ~nicamenteocasionales:regform. jsp,response. j sp, banner. j s py e r r o r . jsp.

Esta clara arquitectura proporcionari una buena base que cualquier futura mejora realizada a la aplicaci6n.

Capitulo 10

Estrategias de diseno JSP


Hasta ahora hemos hablado de c6mo se ejecutan las piginas JSP dentro de un contenedor y de 10s aspectos pricticos de etiquetas y directrices JSP. Examinemos ahora algunos de 10s paradigmas de disefio que pueden utilizarse con paginas JSP para asegurarnos que desarrollamos aplicaciones limpias y mantenibles. Las piginas JSP son un mod0 genial de presentar contenido dinimico per0 no solucionan todos 10s problemas del desarrollo de aplicaciones Web mantenibles. La experiencia ha demostrado que utilizar piginas Web para gestionar la totalidad de la interfaz Web de una aplicacion puede crear tantos problemas como soluciones. Existe un verdadero peligro en el uso de piginas JSP de forma inapropiada. Las piginas JSP en sistemas de producci6n son dificiles de leery de mantener. A menudo consisten en c6digo Java en scriptlets y anotaci6n HTML, con transiciones entre niveles de abstracci6n que ninglin desarrollador experimentado toleraria en una aplicaci6n Java. Mientras que el lenguaje Java por si so10 hace un buen trabajo ayudando a 10s desarrolladores a escribir c6digo mantenible, JSP proporciona muy poca ayuda y muchas tentaciones de escribir c6digo desordenado que ni siquiera se ajusta a la reutilizaci6n de procedimiento. El punto clave es la mantenibilidad; cuesta mucho mis mantener la pieza media de software que escribirla por primera vez. Es importante que las piginas JSP n o contengan una cantidad excesiva de contenido Java. Si contienen muchos scriptlets, supondrin un problema de mantenimiento tanto para desarrolladores de Java, que pueden n o ser expertos en anotaci6n compleja, como para disefiadores de piginas, que pueden confundirse por culpa de Java y romperlo por equivocaci6n a1 retocar y manipular la pigina. Normalmente, este problema indica que la arquitectura subyacente no esti muy bien disefiada. Recuerde que las paginas JSP complementan a 10s senlets: no 10s sustituyen. Las aplicaciones Web complejas emplearin servlets y piginas Web en aquellas tareas en las que funcionan mejor. Ahora que ya e s t i familiarizado con 1as piginas JSP y 10s senlets, revisemos 10s puntos fuertes y Ids puntos dkbiles de cada uno de ellos. Los senlets son la linica opci6n para generar contenido binario. Tambikn son mejores en la ejecuci6n de la logica de control. C o n frecuencia, n o sabemos con exactitud quC deberia ser mostrado o c6mo deberia ser formateado, hasta que hemos llevado a cab0 el procesamiento que puede conllevar el acceso a datos de empresa. Por ejemplo, si intentamos acceder a una base de datos y fallamos, quizis queramos mostrar una vista completamente diferente de la que mostrada en recuperaciones de datos efectivas. Para manejar estas situaciones, utilizar un controlador de servlet para ejecutar el procesamiento y enviar despuCs a la vista JSP apropiada es una elegante soluci6n> Cuando necesitamos realizar alglin tip0 de procesamiento, antes de saber quC deseamos mostrar y posiblemente c6mo debemos formatearlo, un senlet es mejor elecci6n que una pigina JSP. Puede realizar el procesamiento antes de elegir una vista JSP para enviar la solicitud para la presentation final. Las piginas JSP son mucho mejor que 10s senlets en cuanto a presentaci6n de anotacibn. Esto es asi porque la generaci6n de anotacion a partir de c6digo Java es inc6moda de programar y dificil de mantener. Por otro lado, una JSP que consiste en su mayor parte en HTML o XML con una cantidad limitada de contenido dinimico integrado es ficil de leery mantener. En otras palabras, las piginas JSP son mis convenientes como componentes de vista. Una vista es una presentaci6n de pantalla del estado de un modelo de datos. Normalmente, el modelo seri un bean de Java, a1 que se accede por una JSP de vista utilizando la accidn estindar <useBean> que ya hemos analizado. Cuando sabemos quk queremos mostrar y c6mo queremos mostrarlo y contamos con todos 10s datos que necesitamos para presentar en forma de JavaBeans, una vista JSP es la elecci6n correcta. Los requisitos de aplicaci6n varian en complejidad y no existe ;na linica soluci6n correcta para todos 10s problemas. DespuCs de considerar algunos de 10s temas, examinemos algunas de las opciones mis importantes en disefio JSP, comenzando por enfoques ficiles de programar.

Fundamentos v arauitectura de JSP


Existen dos enfoques principales para el diseiio JSP:
0

Disefios centrados en la pigina. En estos disefios, las solicitudes son realizadas directamente a la pigina JSP que produce la respuesta. Tambien son denominados en ocasiones disefios JSP Modelo 1. Diseiios de controlador o lanzador, en 10s que la solicitud es inicialmente realizada a una JSP o a un servlet que actua como mediador o controlador, lanzando solicitudes a piginas JSP y JavaBeans, segun sea apropiado. En ocasiones, son denominados disefios JSP Modelo 2.

Disenos centrados en la pagina o cliente-servidor


En este enfoque, las piginas JSP o 10s servlets acceden a 10s recursos de empresa (una base de datos, por ejemplo) directamente o a travks de un JavaBean, y generan la respuesta por si mismos:

Navegador el chente

son Interceptadai aqul

Navegador el chente

Navegador el cliente

1
I

Enterpr~se JavaBeans

Base de datos

La ventaja de este tipo de enfoque es que es sencillo de programar y permite al autor de la pigina generar contenido dinimico ficilmente, basindose en la solicitud y el estado de 10s recursos. Sin embargo, esta arquitectura no rinde bien cuando aumenta la complejidad de la aplicaci6n y su uso indiscriminado provoca normalmente un exceso de c6digo Java integrado en las piginas JSP. Existen dos variantes principales: la arquitecturavista de pigina y la arquitectura vista de psgina con bean.

Wsta de pagina
La arquitectura bisica conlleva invocaciones de solicitud directa a una pigina JSP compuesta por c6digo Java integrado (scriptlets) y etiquetas de anotacidn que generan dinimicamente salida para sustituci6n en HTML.

Capitulo 10
Es muy ficil iniciarse y es un enfoque de bajo sobregasto desde el punto de vista del desarrollo. Todo el cddigo Java puede ser integrado en HTML, por lo que 10s carnbios quedan confinados a un area limitada, reduciendo la cornplejidad. La siguiente figura muestra esta arquitectura:

La gran concesidn aqui esti en el nivel de sofisticacidn. A rnedida que crece la escala del sisterna, las lirnitaciones de este enfoque, corno incluir dernasiada bgica de empresa en la pigina, salen a la superficie. Corno verernos, el uso de una JSP rnediadora o de componentes de servlet o JavaBeans nos permite separar mis claramente las funciones del desarrollador y mejora el potencial para la reutilizacidn de cbdigo.
La arquitectura de vista de pigina es muy prictica para prototipado ya que es ficil obtener ripidos resultados. Es el enfoque que utiliza la mayoria de desarrolladores a1 enfrentarse a JSP por primera vez. Sin embargo, es muy poco sofisticado para ser utilizado en aplicaciones que no Sean triviales y cotidianas.

Vista de pagina con bean


Esta arquitectura es una versidn elaborada del mismo enfoque bisico cuando la arquitectura de vista de pigina se vuelve demasiado desordenada con cddigo relacionado con la empresa y cddigo de acceso de datos. La arquitectura evoluciona ahora hacia un disefio mas sofisticado, corno muestra la siguiente figura.

-----I JSP

trabajador

Procesam~ento de ernpresa

El cddigo Java que representa la 16gica de empresa y una sencilla implementacidn de almacenamiento de datos ha pasado de la JSP al&vaBean trabajador. Este cambio deja una JSP mucho mis lirnpia que cddigo Java limitado, que puede ser cdmodamente adoptado por un particular en un rol de produccidn Web, puesto que encapsula la mayoria de etiquetas de anotacibn. Adicionalrnente, un individuo menos tecnico podria ser provisto de hojas de propiedad para 10s trabajadores JavaBean, proporcionando un listado de propiedades que son puestas a disposicidn de la pigina JSP por el bean trabajador particular y la propiedad deseada puede ser sencillarnente conectada en la accidn < j s p : g e t p r o p e r t y > de JSP para obtener el valor atributo. Ademis, hemos creado ahora un bean que un desarrollador de software puede poseer, de mod0 que su funcionalidad puede ser refinada y rnodificada sin necesidad de cambios en HTML o anotaciones en la

Fundamentos v arauitectura de JSP


pigina fuente JSP. Hemos creado abstracciones rnis limpias en nuestro sistema reemplazando implementaci6n con objetivo. La aplicaci6n de muestra de Apoyo TCcnico JSP que acabamos de analizar, ha utilizado un formulario de arquitectura de vista de pigina con bean.

El patron de controlador frontal


El enfoque de vista de pigina con bean es una mejora significativa en la arquitectura bisica de vista de pigina. Sin embargo, todavia deja las paginas JSP a falta de ejecutar (0, a1 menos, iniciar) el procesamiento de solicitud y a falta de presentar el contenido. Estas tareas son bastante distintas para muchas piginas y el procesamiento de solicitudes puede resultar complicado. Si una JSP es una vista, la idea de que debe manejar solicitudes entrantes a la aplicaci6n a la que pertenece es claramente err6nea.iCbmo sabemos que esta JSP es la correcta en todos 10s casos? tC6mo debe reaccionar a errores recuperables? (Presentar una pigina de error puede ser una reacci6n excesiva.) Algunas paginas JSP pueden necesitar manipular la sesion, recursos de toda la apkaci6n o estado antes de que la respuesta pueda ser generada. Otras quizis que necesiten examinar valores de solicitud para comprobar si deben redirigir la solicitud. Asociar simplemente propiedades de solicitud a un bean (vkase el anilisis posterior de beans JSP) no es una soluci6n universal, especialmente si se requiere una redirection. Si se encuentra con estos problemas al crear una aplicaci6n Web JSP, es una clara indicaci6n de que el disefio necesita ser revisado. Afortunadamente, existe una conocida y elegante soluci6n, a menudo denominada Arquitectura JSP Modelo 2. Mis recientemente, a1 ser incluida en el catilogo de Sun Java Center J2EE Patterns, ha sido bautizada como patr6n de controlador frontal. Es un intento de aplicar la arquitectura Model-View-Controller (MVC) a las aplicaciones Web. La arquitectura MVC fue documentada por primera vez para las interfaces de usuario de Smalltalk y ha resultado ser una de 10s patrones de arquitectura 00 de rnis Cxito. (Es tambiCn la base de paquetes de interfaz Swing de Java.) MVC divide 10s componentes necesarios para construir una interfaz de usuario en tres tipos de objetos:

o U n objeto modelo de datos o aplicacion


0 Objetos de vista para ejecutar la presentaci6n de pantalla de la aplicaci6n
0

U n objeto controlador para reaccionar a la informaci6n de entrada de usuario

El patr6n Controlador frontal para aplicaciones Web de Java supone tener un senlet controlador o una JSP como unico punto de entrada de una aplicaci6n completa o grupo de piginas. Este punto de entrada no produce salida por si mismo per0 procesa la solicitud, opcionalmente manipula el estado de sesi6n y aplicacion y redirige solicitudes a la vista JSP apropiada o a un sub-controlador que sabe como manejar un subgrupo de todas las solicitudes de la aplicaci6n. Los modelos son proporcionados por beans de Java creados o gestionados por el controlador y puestos a disposici6n de las vistas JSP. Las implementaciones del Controlador frontal incluyen con frecuencia una acci6n o parimetro nombrado de forma similar en cada soJcitud. El valor de este parimetro es examinado por el controlador, que lo utiliza para decidir c6mo procesar la solicitud. Alternativamente, el senlet o JSP controlador puede interceptar todas las solicitudes entrantes y determinar la estrategia apropiada de procesamiento basada en el URL de solicitud. La arquitectura del controlador frontal es uno de 10s enfoques rnis valiosos para construir sistemas JSP sostenibles. Es un verdadero patron de diserio para piginas JSP. Los sistemas construidos mediante su uso tienden a ser rnis flexibles y ampliables que 10s que han sido construidos utilizando un enfoque centrado en la pigina y alcanzan una separaci6n mucho rnis conseguida entre presentaci6n y contenido.

Capitulo 10

Implementation de una arquitectura de controlador


frontal
El patron de controlador de solicitud puede ser implementado en una de las piginas JSP consistentes e n u n largo scriptlet y e n generacidn H T M L nula, per0 esta implementacidn n o es nada elegante. Las clases Java, n o las piginas JSP, son el lugar id6neo para la b g i c a de control. Compare, p o r ejemplo, la definicidn de mktodos e n piginas JSP y clases Java. La sintaxis de declaracidn JSP es poco elegante y n o permite una oportunidad para utilizar Javadoc, o para exponer mCtodos a otros objetos. U n a mejor alternativa es utilizar u n controlador de servlet o hacer que u n controlador JSP delegue la 16gica de control e n una clase controladora. Consideremos una sencilla implementation de arquitectura de controlador de solicitud utilizando u n sewlet controlador. Los requisitos minimos s e r i n 10s siguientes:
O U n sewlet controlador para manejar todas las solicitudes entrantes y delegar el procesamiento e n

las clases ayudantes que manejan solicitudes. Observe que el controlador n o deberia realizar el procesamiento p r o si solo, ya que esto provocaria que la aplicaci6n fuera dificil de ampliar.
0

U n a clase ayudante "manejadora de solicitudes" para llevar a cab0 el procesamiento para cada tip0 de solicitud. ( U n "tipo de solicitud s e r i definido por su U R L dentro de la aplicacion, o el valor de u n parametro concreto.) La interfaz RequestHandler definiri u n Gnico metodo, handleRequest 0 , que r e a h a r i cualquier procesamiento necesario en respuesta a una solicitud y devolveri el U R L de la vista JSP que debe representar la respuesta. Esto permitiri a1 controlador delegar el procesamiento de la solicitud a s u sub-controlador, sin saber c 6 m o es implementado el procesamiento. U n a serie de beans de pigina o modelo para proporcionar datos modelos para vistas JSP. Algunas piginas JSP de vista.

a
0

En aplicaciones m6s complejas, puede ser requerido u n objeto sesi6n. ~ s t seria e creado por las clases que manejan solicitudes, que tambikn accederian a 61 y n o seria manipulado p o r piginas JSP. (Recuerde que una vista n o debe cambiar el estado de u n sistema.) H a b r i rnis paginas de vista JSP que manejadores de solicitudes (un manejador de solicitudes puede enviar la respuesta a diferentes vistas, dependiendo del resultado del procesamiento de lbgica). H a b r i c o m o minimo el mismo nGmero de beans de piginas que de vistas. A primera vista, esto puede parecer innecesariamente complejo e n comparaci6n con el modelo centrado e n la pigina JSP Modelo 1. Hay rnis componentes individuales; la ventaja es que cada componente tiene responsabilidades claramente definidas y las clases Java y las piginas JSP son utilizadas alli donde s o n rnis apropiadas. La mayor complejidad conceptual resultari mucho rnis manejable que la complejidad de codigo JSP q u e tiende a resultar de la adopci6n de u n enfoque menos sofisticado. Veamos c d m o pueden encajar las piezas examinado cada componente sucesivamente.
\

Sewlet controlador
H a b r i una instancia del sewlet controlador de la aplicacidn, que manejari todas las solicitudes entrantes. Podemos asociar todos 10s U R L de la aplicaci6n a1 sewlet controlador e n un archivo Web. x m l de WAR, lo que supone q u e 10s U R L pGblicos de la aplicacidn n o corresponderin fisicamente con piginas JSP, sino que serin virtuales. El sewlet controlador n o sabra c6mo manejar cada solicitud individual. Su principal responsabilidad sera decidir quk clase ayudante encargada de manejar solicitudes debe hacerse cargo de cada solicitud y delegar el

Fundamentos v arquitectura de JSP


procesamiento de solicitudes en ella. Si ponemos toda la 16gica de nuestra aplicaci6n en el controlador, terminaremos con una clase monolitica de procedimiento y con toda probabilidad, cadenas de instrucciones i f/els e dificiles de mantener. Seria dificil afiadir nueva funcionalidad. Utilizando la deleeaci6n. podemos " aiiadir nueva funcionalidad muy ficilmente: nuevos tipos de solicitudes pueden ser gestionados por manejadores de solicitudes. Los manejadores de solicitudes son subcontroladores efectivos.
A

El controlador elegiri un manejador de solicitud para cada solicitud basindose en un grupo de asociaciones de tip0 de solicitud a las instancias de manejador de solicitud que mantiene. Estas asociaciones pueden basarse en URL de solicitud o en el valor de un parimetro "action" especial. Aunque n o intentaremos implementarla en este sencillo c6digo de ejemplo, estas asociaciones deben definirse fuera del codigo Java. U n archivo . properties o documento de configuraci6n XML seria ideal. Delegar el procesamiento de solicitud en clases ayudantes y utilizar asociaciones significari que el sewlet controlador sera genkrico; n o necesitari ser modificado o recompilado a medida que cambie la funcionalidad de una determinada aplicaci6n. C o n diferentes asociaciones, el mismo sewlet controlador podria ser utilizado en diferentes aplicaciones.

Manejadores de solicitud
A diferencia del sewlet controlador, las implementaciones de la interfaz Reques tHandler (que analizaremos pronto) serl especifico de la aplicaci6n. Cada manejador de solicitud ejecutari 10s siguientes pasos:
0

Examinar 10s parimetros de solicitudes entrantes

n Actualizar el estado de aplicaci6n si es necesario


0

Obtener cualquier dato necesario para mostrarlo y ponerlo a disposicion de las vistas en forma de atributos de sesi6n o de solicitud. (Las piginas JSP tendran acceso utilizando acciones <jsp:useBean>.) Elegir una vista JSP a la que el controlador enviara la respuesta

Puesto que ]as implementaciones Reques tHandler son clases Java, puede beneficiarse de la orientacion del objeto de Java. Por ejemplo, una aplicaci6n podria incluir una implementacion RequestHandler abstracta que recuperara el estado de sesion del usuario e invocara un metodo abstract0 protegido que debe ser definido por subclases para manejar la solicitud dado el estado de sesi6n. Igual que el servlet de control, las implementaciones Reques t H a n d l e r deben estar a salvo de hilos, ya que serin compartidas por muchos usuarios.

Beans de pagina
~ s t o serin s sencillos objetos Java, construidos por manejadores de solicitudes y configurados como atributos en la solicitud para ponerlos a disposici6n de las piginas JSP de vista utilizando la etiqueta < j s p : useBean>. Los beans de plgina no generarin anotaciones ni ejecutarin ninguna logica. Serln tratados como objetos de s& lectura por las vistas JSP y proporcionarin 10s datos de modelo que requieren las vistas.

Vistas JSP
Las vistas JSP en esta arquitectura n o contendran 16gica de flujo de trabajo. A las vistas se les otorgarln beans que contengan 10s datos que necesitan y simplemente 10s mostrarin, posiblemente utilizando etiquetas personalizadas y 10s datos son complejos. N o tendrin necesidad de examinar 10s parimetros de solicitud; todas las elecciones habrin sido realizadas antes de invocar la JSP. N o cambiarin el estado del sistema.

Capitulo 10
Sin embargo, las piginas JSP desernpefian un papel vital en esta arquitectura. Son las responsables finales de toda la generaci6n de contenido. Observe que necesitarernos dos grupos de nornbres en 10s casos en 10s que un URL de solicitud coincida con el nornbre natural de la vista. Por ejernplo, supongarnos que tenernos un forrnulario de registro y la vista del forrriulario es l o g i n . j s p . Si asociamos el URL l o g i n . j s p a 10s servlets controladores, nunca podrernos rnostrar la vista JSP. Nuestra soluci6n preferida a este problerna es utilizar < p a g e n a m e > . h t m l corno URL publico, asociado el controlador y dejar el URL . j s p corno vista. N o es necesario exponer publicamente el URL . j s p : si un recurso genera HTML, es rnejor dejarlo claro en el URL.

lmplementacion
Exarninernos ahora una posible irnplernentacjon de este enfoque. En primer lugar, considerernos el listado Este r . contiene ununico r n i t o d o , h a n d l e ~ e q u e s (t ) , que cornpleto de l a i n t e r f a z ~ e q u e s t ~ a n d l e seri invocado por el controlador.
package import import import public corn. w r o x . p r o j 2 e e . c h l O ; java. i o . +; j a v a x . s e r v l e t . *; javax.servlet .http.*; interface RequestHandler
{

/++

* *
+

D e v u e l v e e l URL d e l a v i s t a e n c a r g a d a d e g e n e r a r l a s r e s p u e s t a s ( p r o b a b l e r n e n t e urla p i g i n a J S P ) , o n a d a p a r a i n d i c a r q u e l a r e s p u e s t a ya s e h a g e n e r a d o .

*/
String

handleRequest(HttpServ1et.Request r e q u e s t , HttpServletResponse response) throws S e r v l e t E x c e p t i o n , IOException;

La interfaz seri irnplernentada por clases ayudantes especificas de la implernentaci6n en las que el senlet controlador delegari el procesarniento de solicitud. Las irnplementaciones de esta interfaz serin el nucleo de la grada Web de nuestra aplicaci6n y capacitarin a1 controlador para delegar bgica especifica de la aplicaci6n. El valor devuelto del rnktodo h a n d l e R e q u e s t ( ) sera probablemente el URL de nuestra aplicaci6n con una JSP de vista; el algunos casos, podria ser el URL de una pigina HTML estitica, o un senlet dentro de la rnisrna aplicaci6n. U n valor de retorno n u 1 1tendri un significado especial, indicando a1 controlador que la irnplernentaci6n RequestHandler construy6 ella rnisrna la respuesta. Esto es necesario para apoyar esos casos en 10s que una vista JSP no es apropiada: por ejernplo, si necesitarnos crear datos binarios. El senlet controlador exarninari solicitudes entrantes e invocari uno de sus rnanejadores de solicitud registrados para cada solicitud. Escojarnos el rnanejador de solicitud que utilizarernos basindonos en el URL de solicitud dentro de la aplicaci6n Web, tal y corno es devuelto invocando el rnitodo H t t p S e r v l e t R e q u e s t . g e t S e r v l e t P a t h ( ) . E l m i t o d o i n i t ( ) delcontroladorconstruiriunatabla hash de instancias R e q u e s t H a n d l e r , introducida por el URL de solicitud. Si el controlador no encuentra un rnanejador para una determinada solicitud, enviari un c6digo 404 de respuesta H T T P ("Not Found"). (Obviarnente, en aplicaciones reales, quizis querarnos ser rnis tiles a1 usuario en esta situaci6n. Por ejernplo, un controlador rnis sofisticado con acceso a1 estado de sesi6n del usuario podria invocar un rnitodo no especifico de la aplicacidn solicitando el estado de sesi6n para la vista rnis adecuada para instar a1 usuario a continuar la sesi6n.)

Fundamentos v arauitectura de JSP


El listado Cont r o l l e r s e r v l e t sigue. Observe que, para una mayor sencillez, hemos refundido la inicializaci6n de la tabla hash del manejador en el metodo i n i t ( ) : esto es lo que sucederi en la verdadera implementaci6n, que utilizari un archivo externo de configuraci6n y evitari, por lo tanto, dependencias sobre las clases especificas de la aplicaci6n. Tambien hemos utilizado una instrucci6n System. o u t . p r i n t l n en el metodo doGet ( ) para mostrar la ruta de servlet de solicitudes entrantes. Una aplicaci6n de producci6n utilizaria un paquete de registro como Apache log4J en lugar de confiar en la salida de consola:
package com.wrox.proj2ee.chlO;

import j ava. io. * ; import j ava. util. * ; import javax.servlet.*; import j avax.servlet. http. * ;
/**

* Basta con segmentar un Servlet con ayuda d e una * asociaci6n desde el URL d e la aplicaci6n a una * serie d e clases RequestHandler. */
public class ControllerServlet extends HttpServlet
(

/ / Tabla hash d e instancias RequestHandler, introducida por URL d e solicitud private M a p handlerHash = new HashMap( ) ; / / Inicializar asociaciones: no implementadas aqui public void init() throws ServletException ( / / Esto leer6 la definiciones d e asociaci6n y poblar6 handlerHash handlerHash.put("/login.html", n e w com.wrox.proj2ee.chlO.app.ShowRecordRequestHandler()); handlerHash.put("/showInfo.html", n e w com.wrox.proj2ee.chlO.app.ShowRecordRequestHandler());

/**

* * * * */

Basindonos en el URL d e nuestra aplicacibn, elegir un RequestHandler para manejar la solicitud y delegar en 6 1 el procesamiento. Devolver c6digo de error HTTP 404 (no encontrado) si no hay RequestHandler asociado a este URL.

public void doGet(HttpServ1etRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("Contr011er: servlet path i s /" request .getServletPath ( ) + " RequestHandler rh = (RequestHandler) handlerHash.get(request.getServletPath0); if (rh == null) { response.sendError(HttpServ1etResponse.S NOT FOUND) ; I else { / / Si llegamos aqui, tenemos un manejador para esta solicitud String viewURL = r h . h a n d l e R e q u e s t ( r e q u e s t , response); if (yiewURL == null) {
/ / El RequestHandler ha terminado la producci6n: else {

no hacer nada

Capitulo 10
/ / El Requesttlar~dler nos indlca la vlsta a utilizar / / Er~vlar a Bsta la respuesta request.getRequestDispatcher(viewURL).forward(request, response);

Fijese en que ningun elernento de esta clase (aparte de las inicializaciones de asociaci6n refundidas para simplificar el ejemplo) es especifico de una aplicacidn concreta. El c6digo Java para nuestra aplicaci6n residiri en sus implementaciones de manejador de solicitud. Para ilustrar c6mo quedar, imagine que estamos construyendo una sencilla aplicaci6n que muestra 10s datos que albergamos sobre usuarios en nuestro almackn de datos (probablemente una base de datos relational, per0 no haremos que nuestras piginas JSP dependan de tales detalles de bajo nivel). El punto de entrada a nuestra aplicaci6n seri showInfo .html,que instari a1 usuario a introducir su nombre si no es conocido por el sistema y mostrar su registro de 61. Habri una pigina que permita a1 usuario corregir su nombre si no se encuentra ningun dato para el nombre enviado. El URL showInf o .html seri manejado por una implementaci6n RequestHandler.Cada uno de estos casos (nombre de usuario no enviado, datos no encontrados para el nombre de usuario y nombre de usuario no encontrado) requeriri una vista distinta. Este es un buen ejemplo de un aspecto crucial de la arquitectura de controlador de solicitud: un URL (y, por lo tanto, un manejador de solicitud) puede poducir diferentes vistas en diferentes circunstancias.
r e q u e r i d a ~ h o w ~ e c o r d ~ e q u e s t ~ a n Como d l e r . la Llamemos alaimplementacibn~e~uest~andler recuperaci6n de datos noes especifica de laweb, ShowRecordRequestHandler utilizari una clase ayudante externa a la grada Web para ejecutar la busqueda de datos. Un listado de ShowRecordRequestHandler tendri este aspecto. Para enfatizar la distincion entre funcionalidad de controlador genkrico y c6digo especifico de aplicacihn, este manejador de solicitud y sus clases de apoyo residen en un paquete separado, corn.wrox .proj2ee.ch12 .app,de la clase controladora y la interfaz RequestHandler:
package com.wrox.proj 2ee. ch10.app;

import j a v a . i o . + ; import javax.serviet. * ; import javax.servlet.http.*;

/** * Mostrara 10s datos que albergarnos sobre el usuario,


*
1 1

o b l i ~ r aa1 usuario a introducir s u nombre d e rnodo que podarnos implemerits RequestHandler

* buscarlos */
public class ShowRecordRequestHandler private DataStore datastore; public S h o w R e c o r d R e q u e s t H a r ~ d l e (r ) datastore = new DataStore ( ) ;
1
{

/** * devuelve el U R L d e la vista que d e b e representar la respuesta * (probablemente una J S P ) o null para indicar que la respuesta ya ha sido + producida y el procesamierlto esti cornpleto.

Fundamentos v arsuitectura de JSP


*/ public String har~dleRequest (HttpServletRequest request, HttpServletResponse r e s p o n s e ) throws ServletException,IOException { String name = request .getparameter ( " r ~ a m e "; ) if (name == r ~ u l l ) { return "enterName. j sp"; ] else { / / Realizar bfisqueda d e base de datos para el usuario DataBean dataBean = dataStore.getInfo(name); if (dataBean == null) { return "sorryNotFound.jsp"; ] else { / / Terlemos datos para este usuario / / crear objeto modelo basado en 10s datos recuperados / / DataModelBean dataBean = recuperar datos y crear objeto r e q u e s t . setAttribute ("dataBearI", d a t a B e a n ) ; return "showInfo. jsp";

La primera tarea de esta clase es examinar la solicitud y buscar un padmetro name. Si n o se encuentra ningun parimetro name, S h o w R e c o r d R e q u e s t H a n d l e r enviari a1 usuario la vista "introducir nombre". Si hay un parimetroname, ShowRecordRequestHandler utilizad una clase ayudante para buscar 10s datos. Si n o se encuentran datos, enviari a1 usuario a la vista "not f o u n d . El caso m i s interesante es aqukl en el que 10s datos son recuperados para un usuario. En este caso, necesitamos poner estos datos a disposici6n de la vista JSP antes de devolver su URL. Realizamos esto creando una bean de pigina para albergar 10s datos y afiadikndolo a la solicitud como un atributo. Esto permitiri a una vista JSP recuperarlo utilizando la etiqueta< j s p : u s e B e a n > . La implementaci6n del bean de pigina es muy sencilla: es un bean de Java que expone las propiedades necesarias y proporciona un constructor de conveniencia tomando todos 10s argumentos requeridos:
package
com.wrox.proj2ee.chlO.app;
{

public class DataModelBean

/ / Alberga valor d e propiedad private String forename;

rlombre

/ / Alberga valor d e propiedad apellido private String surname; / / Alberga valor d e propiedad private S t r i r ~email; / / crea un nuevo DataBean public DataModelBean ( ) {

e-mail

public DataModelBean(String forename,String surname,String email) { this. forename = forename; this. surname = surname; this.emai1 = email;

I
/ * * Getter for property forename * ereturn Value o f property forename.

Capitulo 10
*/
p u b l i c S t r i n g getForename ( ) r e t u r n forename;
{

/ * * S e t t e r f o r p r o p e r t y forename * @ p a r a m f o r e n a m e New v a l u e of p r o p e r t y */
p u b l i c void setForename(String t h i s . forename = forename;
)

forename
{

forename)

/ * * G e t t e r f o r p r o p e r t y surname. * @ r e t u r n Value o f p r o p e r t y surname. */


p u b l i c S t r i n g getsurname ( ) r e t u r n surname; 1
{

/ * * S e t t e r f o r p r o p e r t y surname.

* @ p a r a m s u r n a m e New v a l u e o f p r o p e r t y s u r n a m e . */
p u b l i c void setsurname ( S t r i n g surname) t h i s . surname = surname;
{

1
/ * * Getter f o r property email. * @ r e t u r n Value of p r o p e r t y e m a i l .

*/ public String qetEmail() { r e t u r n email;

I
/ * * S e t t e r f o r property email. * @ p a r a m e m a i l New v a l u e o f p r o p e r t y e m a i l
*/
p u b l i c void setErnailiString this.emai1 = email; email)
[

I
)

Puesto que el proceso de bhqueda de datos no es especifico de la Web, proporcionamos una clase ayudante para implementarlo. Observe que una verdadera implementaci6n de Dat ast o r e buscari tanto una fuente de datos de empresa como una base de datos o quizis conecte a un servidor EJB. En este caso, simplemente hemos poblado 10s valores de datos en-linea:
package import public

com.wrox.proj2ee.chlO.app;
java.util.*; class Datastore
{

/ / HashMap d e o b j e t o s Data'WodelBean i n t r o d u c i d o s p r i v a t e s t a t i c Map d a t a M a p = new HashMap( ) ;


static [ dataMap. put ( " r o d " , new

por

nombre

de

usuario

DataModelBean ( " R o d " , " J o h n s o n " , " r o d . j o h n s o n @ i n t e r f a c e 2 1 corn")) . d a t a M a p . p u t ( " d e t e c t i v e " , new DataModelBean ( " S h e r l o c k " , " H o l m e s " ,

;
);

"supersleuth@22lb.co.uk")
dataMap.put("watson", new DataModelBean("John", "Watson",

Fundamentos y arquitectura de JSP

/ / Crear un nuevo DataStore public DataStore ( ) [


1

public DataModelBean getInfo(String username) 1 return (DataModelBean) dataMap.get (username) ;

I N o piense que necesita utilizar la etiquetac j s p : u s e B e a n > para instanciar beans JSP. Recuerde que hay una forma muy ~ t ide l esta etiqueta que no especifica una clase de implementaci6n, que lanza una excepci6n si un objeto asi no esti definido en la sesi6n o en la solicitud HTTP. Simplemente, omita el atributo de clase de la etiquetac j s p :u s e B e a n > y especifique s610 el tipo, de este modo:

Los beans utilizados en piginas de este tip0 pueden ser instanciados mediante una etiqueta

< j s p : u s e B e a n > completo en otra JSP o puede ser situado en la sesi6n o solicitud por un controlador.
Como estamos utilizando una capa distinta de objetos de datos como modelos, 10s mismo objetos de datos podrian tambikn ser utilizados para proporcionar datos para una interfaz Swing. Observe que es aconsejable recuperar todos 10s datos antes de invocar cualquier vista JSP; una vista no debe acceder a 10s datos lentamente, ya que esto puede provocar fallos inesperados que no pueden ser manejados por el controlador. Tambikn es importante para las vistas evitar depender del c6digo especifico de fuente de datos. Las vistas de pigina JSP no contendrin 16gica. Como cada vista JSP representa un resultado determinado del procesamiento de una solicitud, las arquitecturas de controladores de solicitud requeririn normalmente mis piginas JSP que diserios centrados en piginas JSP Modelo 1. ~ s t o son s 10s listados que muestran c6mo deben quedar las tres vistas JSP. Por supuesto, el HTML seria mucho mis complejo en una aplicaci6n real. Pero debido a que estas piginas no contienen bgica, un disefiador de pigina podria actualizarlas sin alterar la funcionalidad de la aplicaci6n. s h o w I n f o . j s p es una pigina dinimica, que toma informaci6n del bean modelo creado por .h t m l : ~ e q u et s~ a n d l e para r el U R L p ~ b l i c o s h o w ~ o nf

% Access bean placed in the request by S h o w I r ~ f o R e q u e s t H a r ~ d l e r% > <j s p : useBean id="dataModelBean" scope="request" type="corn.wrox.proj2ee.chl0.app.DataModelBear1" / > <

Welcome <b><%=dataModelBean.getkorename ( ) % > <%=dataModelBean.getSurname <p/>The email address w e hold for you is <i><%=dataModelBean.getEmail()%></i>

( )

%></b>!

<p/>Una aplicaci6n real necesitaria rnostrar inforrnaci6n m6s cornpleja.. . Las etiquetas personalizados pueden ayudar a rnostrar datos rn6s cornplejos.

Capitulo 10
entername. jsp es estitico. Sin embargo, es conveniente realizar una JSP en caso de que queramos aiiadir contenido dinimico m i s adelante:

<

% No

necesita

un

bean:

de

hecho

podria

ser

una

pigina

est6tica

% :

< f o r m method="GET" a c t l o n = " s h o w I n f o . h t m l " > P l e a s e e n t e r y o u r name: <input t y p e = " t e x t q ' narne="narne" v a l u e = " " </form>

/>

Asimismo, s orryNot Found.jsp es unapigina estitica:

el 1 . 1 s u a r i o

T a m b i e r , p o d r i a r r ~ o s u t i l i z a r url isearl a q u i p a r a a l b e r g a r h a e n v i a d o , q u e n o hemi,s p d i d o b u s c a r - % >

e l

nornbre

que

S o r r y , we c ~ u l ~ i n ' fti r l d y o u i n o u r d a t a b a s e . Maybe y o u e r l t e r e d y o u r name i n c o r r e c t l y . P l e a s e <a h r e f = " l o g i n . h t m l " > t r y a g a i n < / a > .

El siguiente archivo sencillo Web. xml registrar5 el servlet controlador con la miquina de s e n l e t y asociari 10s URL publicos (login.html y showInfo .html) a1 controlador:

<'DOCTYPE W e b - a p p PUBLIC ' - / / S u n M1cro-~y?terns, Inc.//DTD 'http://]ava.sun.com/dtd/Wet.-app 2 . 3 . d t d f 2 2.3//EN1

Web A p p l l c a t i o r ,

C r e e ahora un archivo W A R (MVC .war)que contenga todos 10s archivos en la siguiente estructura de directorio:

Fundamentos y arquitectura de JSP

Inicie el servidor J2EE y despues la herramienta de despliegue. Cree una nueva aplicaci6n y anidale el archivo WAR. Despliegue ahora In aplicacion p o n i e n d o ~ v c como c o n t e x t Name. Todm Ins solicitudes para URL registrados irbn a ShowRecordRequestHandler. Solicitar s h o w I n f o .h t m l sin proporcionar un padmetro nombre provocari que ~howRecord~equest~andl envie e r la r c s p u e s t a a e n t e r ~ a m e .js p :

Archvo

Edc~on Ver

Favorltos
- -

Herramlentas

Ayuda

--

---

.-

I
A

Please enter your name:

7
9 Local intranet

II
D

Si un nombre n o reconocido, con10 d a n i e l , es introducido, S h o w R e c o r d R e q u e s H a n d l e r enviari la respuestaasorryNot Found. j s p :

_r_l
Sowj, we couldn't h d you in our database. Maybe you entered your name incorrectly. Please tr; ag=isi.

$1

Listo

Capitulo 10
Si un nombre reconocido, como detective, es introducido, el usuario veri 10s detalles asociados a ese nombre. El ShowRecordrequestHandler habrl buscado en el almacin de datos, habri creado un objeto D a t a S t o r e d B e a n y 10s habri puesto a disposition como un atributo de solicitud, antes de enviar lasolicitud a s h o w I n f o . j s p :

(1

Welcome Sherlock Holmes! The emad address w e hold .For you is srrperderr~h@2~b.co.uk

A real application would need to show more complex mformation... Custom tags (see Chapter 11) can help to display more complex data.

Este ejemplo ignora la complejidad de 10s datos de una aplicaci6n real y del acceso a datos pero implementa claramente la arquitectura MVC, dejando claro c6rno podria mejorarse para cumplir 10s requisitos del mundo real. Queda claro ddnde estaria el c6digo adicional: con toda probabilidad, el c6digo JDBC en la chse D a t a s t o r e , las propiedades adicionales en la clase D a t a M o d e l B e a n y la exposici6n de propiedades adicionales (pero sin la introduccidn de 16gica de control) en las vistas JSP. Si se encontrari cualquier excepcidn en el acceso a 10s datos, seria manejada por las clases D a t a s t o r e y S h o w R e c o r d R e q u e s t H a n d l e r . Esto significa que podemos codificar nuestras JSP sin preocuparnos por la necesidad de manejar errores de bajo nivel. (Podriamos utilizar otra JSP, invocada en caso de un error del sistema.)

Ventajas

Las piginas JSP producidas utilizando una arquitectura de controlador frontal tendrin el nivel correct0 de responsabilidad y 10s scriptlets s61o serin necesarios si participan genuinamente en la presentacion. Hay mis ventajas en la ejecuci6n de todos 10s URL de aplicaci6n a traves de un dnico punto de entrada. Por ejemplo, es ficil implementar un control consistente del funcionamiento, registro, indicacidn de errores y seguridad. H e dirigido un equipo de implementaci6n de una arquitectura de controlador frontal en un sitio Web complejo de alto volumen. Nuestro sisterna de controlador de propiedad ofrece una funcionalidad mucho mis rica que la que acabamos de ver per0 10s conceptos bisicos son 10s mismos. Una libreria de etiquetas personalizadas maneja la presentacion de datos cornplejos en vistas JSP. Una jerarquia de rnanejadores de solicitud abstrae la funcionalidad comdn, rnientras que el sistema ofrece una gestidn sofisticada del estado de sesi6n. (Siguiendo el principio de que las vistas no deben manipular el estado de aplicaci6n,los objetos de sesidn no son accesibles para las piginas JSP.) Mediante un disefio JZEE concienzudo, s d o la 16gica de aplicacidn especifica de Web es incluida en la grada Web. Las ventajas son muy notables. Todas nuestras aplicaciones utilizan el mismo sistema de controlador y la misma estructura bisica:

Fundamentos v arquitectura de JSP


0
O

Casi todas las piginas JSP pueden ser mantenidas por el equipo de disefio La seguridad es manejada por el controlador y es transparente para las vistas JSP

0 El rendimiento detallado y las estadisticas de uso estin disponibles para todas las aplicaciones sin necesidad de escribir c6digo especifico de aplicacion 0 El servlet controlador maneja la informacidn de errores de forma transparente y de un mod0 consistente

Como ya habra observado, nuestro ejemplo anterior no intenta manejar errores. U n servlet de controlador realista ofreceri registro de errores y un mecanismo anilogo para piginas de error JSP.

Utilizar un sistema de controlador generic0


Aunque es importante comprender el disefio relacionado y c6mo proceder para implementarlo, una buena opci6n puede ser utilizar un sistema genkrico de controlador de solicitud. Struts, de Apache Project, es un product0 de este tipo, en fuente abierta. VCase http://jakarta.apache.orglstruts/index.html para mas detalles. Struts pretende proporcionar un mktodo flexible controlador de vistas para el desarrollo de Web Java. El componente mis importante es un servlet controlador genkrico, que es configurado fuera del codigo Java y que lanza solicitudes a clases A c t i o n provistas por el desarrollador de la aplicaci6n. (Este enfoque es muy similar a1 que acabamos de analizar.) Struts tambiCn proporciona c6modos etiquetas personalizadas y cumple la asociacion de datos utilizando la reproduccidn Java. Struts solo esti empezando a utilizarse per0 si consigue despertar el interks (y la contribution) que merece de 10s desarrolladores Web de Java, puede que aporte importantes beneficios en productividad y mantenibilidad.

Hemos hablado sobre sintaxis, constructores y semintica de JSP, y hemos visto una aplicaci6n completa que ilustra la funcionalidad central de JSP. Tambikn hemos analizado paradigmas de disefio para aplicaciones JSP. Todavia quedan muchos temas por tratar pero, con lo que hemos visto en este capitulo y sus conocimientos de HTML.. ~ u e d emDezar e a desarrollar a~licaciones Web dinimicas de base TSP. La sintaxis JSP no es muy complicada per0 lo que, si comprende lo que hemos presentado en este capitulo, ya esti preparado para producir piginas JSP. Por el momento, debe haber comprendido:

0 C6mo una pigina $SP es compilada en un servlet por el contenedor 0 La distincih entre periodo de traducci6n y periodo de solicitud
0

Las directrices y acciones JSP y c6mo integrar c6digo Java y expresiones en paginas JSP C o m o utilizar beans de Java desde piginas JSP

0 Los objetos implicitos disponibles para piginas JSP y el concept0 de alcance de objeto 0 Puntos y estrategias para disefiar aplicaciones Web mantenibles y ampliables para hacen un mejor uso de JSP

TambiCn merece la pena recordar que escribir piginas JSP puede ser en ocasiones costoso, especialmente sin un IDE. Esto se debe principalmente a que la depuraci6n de una plgina JSP no es tan facil como la

Capitulo 10
depuraci6n de un programa Java son j db o su purificado favorito. Necesita purificar el senlet generado y relacionarlos con la fuente JSP; hay unos cuantos productos en la actualidad que le permiten realizar este proceso (como Hendiri y Jbuilder). Remitase a la documentacidn adjunta a su miquina de servlet para mis informaci6n sobre su apoyo para la purificaci6n integrada utilizando IDE conocidos. En el siguiente capitulo, avanzaremos para analizar una importante caracteristica de la especificaci6n JSP: las extensiones de etiqueta. Las extensiones de etiqueta, como JavaBeans, nos ayudan a evitar el exceso de contenido de c6digo Java en piginas JSP. N o s61o afiaden funcionalidad a la sintaxis JSP estindar sino que tambien proporcionan mantenibilidad de aplicaci6n.

Extensiones de etiqueta de JSP


Probablemente, la incorporaci6n mas importante de la especificaci6n JSP 1.1 sea el apoyo a extensiones de etiqueta (etiquetas personalizadas). Este apoyo esti reforzado en la especificaci6n JSP 1.2, confirmando que las extensiones de etiquetas son una de las caracteristicas mis importantes de JSP. Las extensiones de etiqueta se parecen mucho a etiquetas estindar HTML o XML integrados en una pigina JSP, per0 tienen un significado especial para la miquina JSP en el periodo de traducci6n y permiten que la funcionalidad personalizada sea invocada sin tener que escribir c6digo Java en scriptlets. Esto permite a1 desarrollador JSP invocar la funcionalidad de la aplicaci6n sin tener que conocer ningfin detalle del c6digo Java subyacente. Las bibliotecas de etiquetas tambikn ofrecen apoyo portitil de periodo de ejecuci6n, apoyo de composici6n/modificaci6n y validation. En este capitulo, examinaremos 10s principios bisicos de escritura de nuestras propias etiquetas, incluido:

o Las ideas bisicas de extensiones de etiqueta


0

La anatomia de una extensi6n de etiqueta C6mo desplegar una bibilioteca de etiquetas

0 0

C 6 m o crear extensiones de etiquetas personalizadas Las mejoras del apoyo a extensiones de etiqueta de la especificaci6n JSP 1.2

Comenzaremos analizando d6nde podemos llegar con las extensiones de etiqueta.

Extensiones de etiqueta
Consideremos la acci6n estindar < j s p : f o r w a r d > provista por la especificacidn JSP. Esta etiqueta lanza la solicitud actual a otra pigina JSP dentro de la actual aplicaci6n Web. Puede ser invocada con la siguiente sintaxis:

Capitulo 11
'1 s p : f o r w a r d page="next .]sp"

/>

TambiCn podemos afiadir parimetros adicionales a la solicitud antes de enviarla, utilizando una versi6n de < j s p : f o r w a r d > que tiene uno o rnis etiquetas < j s p : p a r am> anidados en 61:
< jsp: forward paqe="next. j sp" > < j sp:pararn name="irnageW v a l u e = " h o u s e . g i f "

//. .. </ js p : f o r w a r d >

/>

Las extensiones de etiqueta permiten una amplia gama de nueva funcionalidad para ser afiadida a piginas JSP y pueden ser invocadas de un mod0 intuitivo, similar a1 de las acciones estindar. Por ejemplo, podriamos crear una etiqueta llamado<wrox : f o r w a r d > , especificar quC atributos y sub-etiquetas requiere (si es que requiere alguno) e implementarlo de mod0 que ejecute una acci6n personalizada antes de enviar la solicitud actual a una nueva pigina JSP. N o s61o estas etiquetas pueden ser simplemente afiadidos en una pigina JSP sino que refuerzan la separaci6n de c6digo y presentaci6n porque la llarnada es escindida de la clase que implements la funcionalidad asociada a la etiqueta. Los conceptos clave de extensiones de etiqueta son 10s siguientes:

Nombre de etiqueta Una etiqueta JSP es identificado de forma exclusiva en una pigina por una combinaci6n de un prefijo (en este caso, j s p ) y un sufijo (en este caso, f o r w a r d ) , separados por un punto y coma. El prefijo identifica una biblioteca de etiquetas (aniloga a un espacio de nombre XML) y el sufijo identifica a una determinada etiqueta de esa bibl'loteca. Atributos Las etiquetas pueden tener atributos (que utilizan sintaxis de atributos XML). Nuestra etiqueta < j s p : f o r w a r d > tiene un atributo ( p a g e ) , mientras que la etiqueta< j s p : param> tiene dos (name y v a l u e ) . Los atributos pueden ser precisos u opcionales. Anidamiento Las extensiones de etiqueta pueden detectar anidamiento en el period0 de ejecucidn y cooperar. Una etiqueta que incluye directarnente otra etiqueta es el progenitor de la etiqueta al que incluye. En nuestro ejemplo, la etiqueta< j s p : f o r w a r d > es el progenitor de la etiqueta< j s p :param>. Cualquier etiqueta que incluya a otra etiqueta, directarnente o de forma mis lejana es un ancestro de la etiqueta incluida. Contenido de cuerpo El contenido de cuerpo es cualquier cosa entre el elemento inicial y el elemento final de una etiqueta JSP, excluyendo 10s sub-etiquetas. Una extension de etiqueta puede acceder y manipular su contenido de cuerpo. Variables de directivas Las etiquetas pueden definir variables que pueden ser utilizadas en la pigina JSP en el contenido de cuerpo de la etiqueta o (dependiendo del alcance de las variables) despuCs de que la etiqueta haya sido incluido. La acci6n estindar< j s p :u s e B e a n > es un ejemplo de una etiqueta que define una variable de directiva disponible para el resto de la JSP. U n a o rnis clases Java implementan la funcionalidad de una etiqueta. El manejador de etiquetas (la clase que implementa la etiqueta) es u n JavaBean, con propiedades que se corresponden con 10s atributos de la etiqueta. U n archivo Tag Library Descriptor (TLD) es u n documento XML que describe una biblioteca de etiquetas, que puede contener una o rnis extensiones de etiqueta. La directriz JSP taglib debe ser utilizada para importar las etiquetas de la biblioteca de etiquetas en cada pigina JSP que desee utilizar cualquier de ellos.

Extensiones de etiaueta JSP


2Por que, ademis de por tener una sintaxis inteligente, podriamos elegir utilizar extensiones de etiquetas antes que utilizar JavaBean en nuestras piginas JSP? 2Por que las extensiones de etiquetas son algo mas que otra forma de conseguir que las piginas JSP puedan repartir el trabajo entre las clases Java? Debido a la fuerte interacci6n entre la pigina JSP host y las extensiones de etiquetas, podemos utilizar las extensiones de etiquetas para conseguir lo que 10s beans solo pueden conseguir en conjunci6n con scriptlets. Las extensiones de etiqueta pueden acceder al objeto i m p l i c i t o p a g e ~ o n t e x t escribir , a1 escritor de salida, redirigir la respuesta y redefinir las variables de directiva. Como dato indicativo de su capacidad, todas las acciones JSP estindar provistas mediante etiquetas en forma < j s p : x x x > podrian ser implementadas utilizando extensiones de etiqueta si asi lo quisieramos. Las extensiones de etiquetas pueden ser utilizadas para repartir una gama de funcionalidad que solo esti limitada por la imaginaci6n del desarrollador (y, por supuesto, por la prictica sensata de la programaci6n). Algunos de 10s usos mis habituales de extensiones de etiqueta son 10s siguientes:
O

Ocultar a1 autor de la pigina la complejidad de acceso a una fuente de datos u objeto de empresa, que quizis n o tenga experiencia con datos de empresa Introducir nuevas variables de directivas en la pigina Filtrar o transformar contenido de etiqueta, o incluso interpretarlo como otro lenguaje

O O

0 Manejar la iteracidn sin necesidad de scriptlets

Las extensiones de etiqueta difieren de JavaBeans en que son bloques comunes de construcci6n, en lugar de recursos a medida para una pigina o grupo de piginas concreto. Las etiquetas reciben 10s atributos que controlan su funcionamiento de la pigina JSP que 10s utiliza, n o de la solicitud dirigida a una deterrninada pigina JSP (como es el caso de las asociaciones de propiedad de bean de solicitud). Consecuentemente, una extensi6n de etiquetas bien disefiada puede ser utilizada en diversas piginas JSP. Esta reusabilidad es especialmente importante. Puesto que la implementaci6n y la interaccidn entre extensiones de etiqueta y la miquina JSP esti bien definidas en la especificaci6n JSP, las biblioteca de extensiones de etiqueta pueden ser desarrolladas y distribuidas. Las etiquetas genkricas pueden ser desarrollados para determinadas industrias o tipos de aplicacibn. Muchos vendedores en la actualidad ofrecen este tip0 de bibliotecas de etiquetas, a menudo como parte de un producto de mayor tamafio como un servidor de aplicaci6n.
/ . Las extensiones de ettqueta, aunque sdlo ban sido introducidas en la JSP 1.1, son un concept0 establecido en la generacidn de paginas dina'micas. Productos como ColdFusion y Webobjects de Apple ban repartido mucha funcionalidad durante muchos aiios gracias a las etiquetas personalizadas (aunque en un context0 de propiedad) y esta experiencia en el uso de etiquetas personalizadas puede ser un recurso valioso para 10s desarrolladores JSP.

Las extensiones de etiqueta son un elemento muy bien acogido por 10s desarrolladores JSP porque son ficiles de implementar. El API que 10s ro+a es relativamente sencillo y es posible utilizarlos para conseguir resultados ripida y ficilmente. Esta es una reproducci6n de la elegancia del disefio del mecanismo de extensiones de etiqueta (en el verdadero espiritu Java, ofrece mucha funcionalidad sin excesiva complejidad). Los ejemplos y la mayor parte del debate de este capitulo y del siguiente asumen que las extensiones de etiqueta serin utilizadas para generar anotaciones H T M L o XHTML. Aunque kste es normalmente su uso mis extendido, las extensiones de etiqueta pueden utilizarse para generar cualquier tip0 de contenido que se ajuste a JSP. Sin embargo, esto n o incluye 10s tipos de contenido binario: 10s servlets deben utilizarse para generar producci6n n o textual.

Capitulo 11

Mejoras de la extension de etiqueta JSP 1.2


Antes de examinar con rnis detalle la infraestructura de extensidn de etiqueta, revisemos ripidamente 10s cambios entre JSP 1.1 y JSP 1.2.

Si no ha trabajado con las extensiones de etiqueta de JSP 1.1, puede que prefiera saltarse esta seccidn por el momento. Sin embargo, como 10s contenedores de JSP 1.2 deben ajustarse a las bibliotecas de etiqueta de JSP 1.1, considerara' este apartado importante en el futuro si se le pide que mantenga el cddigo existente.
Los cambios ~i~nificativos son 10s siguientes:
0

Los autores de la especificacidn han intentado aumentar la capacidad del API de extensidn de etiqueta y facilitar su uso. Hay dos nuevas interfaces para el manejo de etiquetas: I t e r a t i o n T a g , que hace rnis ficil el desarrollo de sencillos manejadores de etiqueta que eval6en repetidamente su contenido de cuerpo; y T r y C a t c h F i n a l l y , que asiste en el manejo de errores. de u t i l i z a r u n a c l a s e ~ a g ~ x t r a o. ~nf

0 Ahora es posible declarar variables de directivas en un descriptor de biblioteca de etiqueta, en lugar 0 Ahora es posible ejecutar una validacidn sofisticada en el period0 de traduccion del uso de etiquetas

en una biblioteca, basindose en la estructura completa de cada pigina JSP que intenta utilizar uno o rnis etiquetas de la biblioteca. Esto se realizautilizindola n u e v a c l a s e ~ a g ~ i b r a r y ~ a l i d a t i o n .
0 Han sido aiiadidos nuevos elementos al TLD para acomodar estos cambios. En un carnbio no

funcional, 10s nombres de muchos elementos han cambiado para incluir guiones: por ejemplo, t l i b v e r s i o n se convierte e n t l i b - v e r s i o n .

O Se ha reforzado el TLD para 10s eventos de ciclo de vida de aplicacion introducidos en la especificacidn Servlet 2.3. Las bibliotecas de etiquetas pueden incluir escuchadores de eventos de aplicacidn, que serin notificados sobre eventos tales como un carnbio en 10s atributos de context0 de servlet.
La buena noticia es que todos 10s cambios son de compatibilidad retroactiva ya que el nuevo API es un superconjunto del API de extensidn de etiqueta JSP 1.1 y se requieren miquinas de servlet adaptables a JSP 1.2 para aceptar las bibliotecas de etiquetas que utilicen el API antiguo y el D T D TLD de JSP 1.1. Sin embargo, esto no significa que las versiones 1.1 y 1.2 de 10s D T D TLD Sean compatibles. Los D T D difieren ligeramente en estructura y significativamente en nombres de elementos. Por ello, a1 mantener una biblioteca de etiquetas JSP 1.1, tenemos dos opciones: podemos dejar el TLD en el D T D 1.1 y realizar 10s carnbios necesarios como si estuvikramos ejecutando JSP 1.1; o podemos elegir modernizar el D T D para equipararlo a1 D T D JSP 1.2 antes de realizar 10s cambios. Los factores decisivos serin probablemente si nos gustaria o n o utilizar cualquiera de las nuevas funciones de JSP 1.2 y si alguna de las instalaciones de JSP 1.1 todavia requeriri la biblioteca de etiquetas.

Observe que aunque podemos utilizar esos elernentos del API de JSP 1.2 accesibles desde el D T D I . I (como la interfaz IterationTag) en una biblioteca de etiquetas con un D T D de JSP 1.1, esto puede resultar confuso para 10s usuarios d d a biblioteca de etiquetas y debe evitarse.

Una sencilla etiqueta


Antes de examinar detenidamente el API de extension de etiqueta y la infraestructura de apoyo, implementemos una sencilla etiqueta. El caso rnis sencillo es el de una etiqueta sin atributos o contenido de cuerpo, que produce HTML. Tambikn aiiadiremos alg6n contenido dinimico para probar que la

Extensiones de etiaueta JSP


etiqueta esti funcionando y desempeiiando una funci6n. Nuestro objetivo es crear una etiqueta que Cree la siguiente informaci6n (10s parkntesis angulares agrupan informacidn dinimica provista en el periodo de * ejecucion):

Hello world. My name is <tag handler implementation class> and it's <date and time>
Llamaremos a nuestra sencda etiqueta h e l l o y asi es c6mo lo utilizariamos en una pigina JSP. La primera linea es una declaracidn utilizada para importar la biblioteca de etiquetas, que analizaremos mis adelante:

<html> <head> <title>First custom tag</title> </head>

<p>Esto es salida estitica. La salida d e la etiqueta es mostrada cursiva.</p> <p><i> <examples:hello> </examples:hello> </i></p> <p>Cerrar la etiqueta sin cuerpo tendri el mismo efecto:</p> <p><i> cexamp1es:hello / > </i></p> < p > ~ s t ~son s d e Nuevo datos d e plant-illa estiticos.</p>

en

Para implementar la etiqueta necesitamos definir un manejador de etiqueta (una clase Java que implemente la funcionalidad de la etiqueta) y proporcionar un descriptor de biblioteca de etiqueta. Podemos entonces importar la biblioteca de etiqueta en cualquier pigina JSP que la requiera. La clase manejadora de etiqueta debe reaccionar a retrollamadas de la miquina JSP cuando encuentre etiquetas en piginas JSP en el periodo de ejecuci6n. Las mis importantes de estas retrollamadas son ( ) ,que es invocada d o s t a r t ( ) ,que es invocada cuando encuentra el principio de la etiqueta y d o ~ n d T a g cuando encuentra el cierre de la etiqueta. La implementaci6n de He1 l o T a g es muy sencilla, puesto la mayor parte del trabajo de implementaci6n de etiquetas personalizadas es realizado por la superclase T a g s u p p o r t provista por el API JSP. N o se preocupe si algunos detalles son algo confusos: analizaremos esta clase, asi como el API que utiliza, con mis detalle dentro de un momento.
package import import import import tagext; java.io.IOExcep lon; java.uti1. Date; javax.servlet. j s p . * ; javax.servlet.jsp.tagext.TagSupport;

7'

La superclase T a g s u p p o r t es una clase de conveniencia proporcionada en el API de extensidn de la etiqueta.Yaimp1ementalainterfazj a v a x s e r v l e t j s p t a g e x t .Tag:

Capitulo 11
public class HelloTaq extends Tagsupport
[

public int d o S t a r t T a g 0 throws JspTagException return EVAL BODY INCLUDE;

El metodo do^ t a r t T a g ( ) s e r i invocado cuando la miquina JSP encuentre el inicio de una etiqueta implementado por esta clase:
public int doEndTag ( ) throws JspTagException { Stl-ing datestring = n e w Date ( ) . tostring ( ) ; try i

Obtenemos el actual J s p W r i t e r a partir del context0 de la etiqueta y escribimos en 61:


pagecontext. getout ( ) .write ("Hello world. <br/>") ; pageContext.getOut( ).write("My name is " + getClass().getName(l t " and it's " + datestring + "<p/>"); catch (IOException e x ) { throw n e w JspTagException ( "Fatal error: hello tag could not write to JSP out");

I
El metodo d o s t a r t T a g ( ) devuelve u n valor que indica si evaluar o n o cualquier contenido de cuerpo que pueda tener esta etiqueta. Los valores legales de retorno son EVAL-BODY-INCLUDE (destinado a evaluar el contenido del cuerpo de la etiqueta y cualquier sub-etiqueta) y SKIP-BODY (que significa que 10s contenidos de la etiqueta serin ignorados):
return EVAL PAGE;

1
I

El m i t o d o d o E n d T a g ( ) s e r i invocado cuando la miquina JSP encuentre el final de una etiqueta implementado p o r esta clase. Devuelve u n valor que indica si la miquina debe evaluar o n o el resto de la pagina JSP. Los valores legales de retorno con EVAL-PAGE (el caso habitual) y SKI P-PAGE. El descriptor de la biblioteca de etiqueta, que llamaremos h e 1 l o . l t d , asocia la etiqueta a la clase manejadora de etiqueta y define el m o d 0 en que las piginas puede interactuar con la c l a s e ~ e l l o ~ a g :

< ! D O C T Y P E taglib PUBLIC "-//Sun Microsystems, Ir,c.//DTD JSP Tag Library 1.2//ENn "http://java.sun.com/dtd/Web-jsptaqlibray 1 2.dtdn> <taglib> <tlib-version>l.O</tlib-versior~> <jsp-versiorj>l.2c/ jsp-versior,>
<short-name>examplesC/short-r~ame>

<description>Simple example

library. Author: Rod

Johr,sor~</descriptirn>

<tag> cname>hello</name> <tag-class>tagext.HellaTagC/tag-class> cbody-content>~S~</budy-content> <description> Simple hello world example. Takes r i o attributes, and simply generates HTML </description> </tag> </taglib>

'

Extensiones de etiqueta JSP


El sufijo de la etiqueta a1 ser utilizado en cualquier JSP debe ser h e l l o y su prefijo es e x a m p l e s a1 ser importado en esta pigina JSP. Por ello, para utilizar la etiqueta en una JSP debemos utilizar <examples:hello>.
Puesto que una biblioteca de etiquetas puede incluir cualquier numero de etiquetas, simplemente ariadiremos elementos < t a g > extra a este descriptor de biblioteca de etiqueta para 10s restantes ejemplos de este capitulo.

Analizaremos las opciones de despliegue para bibliotecas de etiquetas mas adelante pero, mientras tanto, estudiemos c6mo podemos ejecutar este ejemplo en la Implementaci6n de Referencia J2EE. Necesitamos empaquetar el descriptor de biblioteca de etiqueta, las clases Java que implementan las etiquetas de la biblioteca y las piginas JSP que utilizan las etiquetas en un WAR. Esta es la estructura del archivo WAR para este sencillo ejemplo:
h e l l o .j s p WEB-IN/ Web. xml classes/ tagext/ HelloTag.class tlds/ tiello. tld

Hay algunas convenciones WAR especificas para utilizar las bibliotecas de etiquetas. Debemos situar nuestros archivos de descriptor de biblioteca de etiqueta en el d i r e c t o r i o ~ ~ ~ - ~ ~ y el ~/ archivo tlds Web. xml incluye un mapa para permitir a1 servidor saber d6nde encontrar 10s URI y la ruta de recurso TLD. El mapa es descrito utilizando la etiqueta < t a g 1 i b > . ~ s t es e el archivo w e b . xml para nuestro sencillo ejemplo:

< ! DOCTYPE Web-app

PUBLIC ' - / / S u r l Mic-osystems, Inc.//DTD Web Application 2.2//EN1 'http: / / j a v a . s u n . com/ j 2ee/dttds/Web-app 2.2 . d t d l>

Para empaquetar nuestro WAR, ejecute el siguiente comando desde %BOOK-HOME% \chll\.Observe que excluimos 10s archivos fuente . j a v a , ya que inflarian innecesariamente nuestro WAR y pueden causar problemas en el period0 de despliegue:
j a r -cvf hello.war WEB-INF/classes/tagext/+.c1ass WEB-INF/tlds/hello.tld WEB-INF/Web.xml * . jsp

Inicie el servidor J2EE y la herramienta de despliegue. Entonces siga 10s siguiente pasos para desplegar nuestro WAR en el servidor:

Extensiones de etiaueta JSP


0 U n rnanejador de etiqueta es un JavaBean que implementa una de las tres interfaces definidas en el p a q u e t e j a v a x . s e r v l e t j s p . t a g e x t : Tag, 1terationTagoBodyTag.Estasinterfaces definen 10s eventos del ciclo de vida relevantes para una etiqueta y, fundamentalmente, las llamadas a la clase que implements la etiqueta recibiri cuando la miquina JSP encuentre las etiquetas de inicio y de cierre.

0 U n descriptor de biblioteca de etiqueta o TLD, que es un documento XML que contiene informaci6n sobre una o mis extensiones de etiqueta .

Una clase adicional tambikn puede ser especificada en el T L D que ejecuta la validaci6n de personalizaci6n de atributos de etiqueta. Obviamente, las clases que implementan una etiqueta pueden utilizar cualquier ndmero de clases ayudantes, que tambikn necesitarin ser empaquetadas con la etiqueta de modo que sea una unidad completa de despliegue. Antes de que las etiquetas puedan ser utilizadas en una JSP, la directriz taglib debe utilizarse para importar una biblioteca de etiquetas y asociar las etiquetas que contiene a un prefijo. Examinemos cada uno de estos requisitos sucesivamente.

Manejadores de etiqueta
Cuando una miquina JSP encuentra una extensi6n de etiqueta en una pigina JSP en el periodo de traduccibn, analiza el descriptor de la biblioteca de etiquetas para encontrar la clase requerida para el manejo de etiquetas y genera c6digo para obtener el manejador de etiqueta e interactuar con 61. La interfaz implementada por el manejador de etiqueta define retrollamadas que el servlet (creado desde lapigina JSP) realizari a la instancia del manejador de la etiqueta en el periodo de ejecuci6n. Por razones de rendimiento, las miquinas JSP no instanciarin necesariamente un nuevo manejador de etiqueta cada vez que una etiqueta sea encontrado en una pigina JSP. En su lugar, puede que mantengan una reserva de instancias de etiqueta, que pueden ser reutilizadas alli donde sea posible. Cuando se encuentra una etiqueta en una pigina JSP, la miquina JSP intentari encontrar una instancia Tag que no estk siendo utilizada, inicializarla, utilizarla y, finalmente, liberarla (pero no destruirla), dejindola disponible para un uso posterior. El programador no tiene control sobre ninguna reserva que pude tener lugar.

Mientras que el modelo de uso repetido es similar a1 ciclo de vida de un servlet, jijese en que hay una diferencia muy importante: las implementaciones del manejador de la etiqueta no necesitan preocuparse de la seguridad de 10s hilos. La ma'quina JSP no utilizara' una +stancia de un manejador de etiqueta para manejar una etiqueta a menos que este' libre. Estas son buenas noticias: a1 igual que con la composicidn JSP en general, 10s desarrolladores necesitan preocuparse de 10s hilos con menos fiecuencia que durante el desarrollo de servlets. Despue's de que todas las invocaciones Sean completadas, el contenedor invocara' el me'todo release0 del manejador de etiqueta. Asi liberara' cualquier recurso restante y preparara a1 manejador de etiqueta para la recoleccidn de residuos. Muchas etiquetas no necesitan implementar el me'todo release0 y pueden simplemente confiar en la implementacidn por defect0 heredada d e las superclases abstractas provistas por el APZ de extensidn de etiquetas.

La interfaz javax.servlet.jsp.tagext.Tag
La interfaz define una sencilla interacci6n entre la miquina JSP y el manejador de etiqueta, que es suficiente para etiquetas que no necesitan manipular su contenido de cuerpo o evaluarlo repetidamente. Sus mktodos

Capitulo 11
centrales son las llamadas recibidas cuando la miquina JSP encuentra las etiquetas de inicio y de cierre de la etiqueta: d o s t a r t ( ) y doEndTag ( ) . Antes de que examinemos 10s contratos de metodos con mis detalle, un diagrams de secuencias nos ayudari a visualizar las llamadas realizadas el manejador de etiqueta por el servlet compilado. Asumamos que el contenedor ya tiene una instancia manejadora de etiqueta disponible y esti en el estado por defecto:

I release

I I
I

I
I

Examinemos 10s mensajes mis detenidamente:


O El contenedor inicializa el manejador de etiqueta configurando la p r o p i e d a d p a g e ~ o ne t x t del

manejador de etiqueta, que tste puede utilizar para acceder a informacidn disponible para la pigina JSP que la esti utilizando.
D El contenedor configura la propiedad p a r e n t del manejador de etiqueta. ( p a r e n t seri configurado el n u l l si la etiqueta no esti incluidden otra etiqueta.)
0

Cualquier atributo de etiqueta definida por el desarrollador seri configurado. ~ s t es a una asociacidn de 10s atributos XML de la etiqueta a las propiedades correspondientes del bean manejador de la etiqueta. Por ejemplo, en el caso de una etiqueta invocado ask < m y t a g s :t e s t name=" J o h n " a g e = 4 3 />, el contenedor intentari invocar 10s mktodos s e t N a m e ( ) y s e t A g e ( ) sobre el manejador de etiqueta. El contenedor intentari convertir cada atributo en el

Extensiones de etiqueta JSP


tip0 de propiedades bean correspondiente: por ejernplo, el string " 43" sera convertido en un i n t en este caso. Si el tip0 de conversi6n falla, se lanzari una excepci6n y debe ser rnanejada por la pigina JSP llarnante. (Desde el punto de vista de la pigina JSP, no existe ninguna diferencia entre una excepci6n lanzada por un rnanejador de etiqueta y una lanzada por una expresi6n de un scriptlet de la pigina.)

O El contenedor invoca el rnktodo d o s t a r t ~ a g ( ) del rnanejador de etiqueta y despuks el rnktodo doEndTag ( ) .


0

Este rnensaje puede que no aparezca despuks de todas las invocaciones de etiqueta. El contenedor invoca el rnCtodo re lease ( ) . Los rnanejadores de etiqueta difieren de 10s beans de pigina en que su ciclo de vida es cornpletarnente independiente del de las piginas JSP que 10s utilizan. Los rnanejadores de etiqueta deben ajustarse a1 uso repetido antes de la construcci6n, posiblernente en una serie de piginas JSP. La irnplernentaci6n del rnktodo release ( ) debe asegurar que n i n g h recurso requerido durante la ejecuci6n de la etiqueta es liberada. La especificaci6n JSP garantiza que la invocaci6n de release ( ) tendri lugar antes de que el rnanejador de etiqueta sea elegible para la recolecci6n de residuos. La especificaci6n tarnbikn establece que puede haber rndtiples invocaciones para 10s rnktodos d o s t a r t ~ a g ( ) y doEndTag ( ) antes de que la invocaci6n de release ( ) . N o queda cornpletarnente para la especificaci6n si se invocari una instancia del rnanejador de etiqueta despuks de re 1ease ( ) ,per0 se podria deducir que esta invocaci6n no produciri.

Analicernos 10s rnktodos d o s t a r t ~ a ( )~ y doEndTag ( ) :


int doStartTag0 throws JspException
A

~ s t es e invocado d e s ~ u 6 de s sue la etiaueta haya sido inicializado, cuando la rnisuina " TSP encuentra el inicio de una etiqueta en el periodo de ejecuci6n. Su valor de retorno debe ser una de las dos constantes definidas en la interfaz Tag: EVAL-BOY-INCLUDE, que instruye a la rniquina JSP para evaluar el cuerpo de la etiqueta y cualquier etiqueta descendiente que tenga, o SKI P-BODY, que instruye a la rniquina JSP para que ignore el cuerpo. Este rnCtodo puede lanzar una JspException,(a1 igual que la rnayoria de 10s rnCtodos del API del rnanejador de etiqueta cuando se encuentra con una condici6n de error) per0 su rnanejo dependeri de la pigina JSP que estC utilizando la etiqueta. La rnayoria de las piginas JSP utilizarin una pigina de error, por lo que una excepci6n lanzada en una etiqueta abortari norrnalrnente la
int doEndTag 0 throws JspException

doEndTag ( ) es invocado cuando la rniquina JSP encuentra la etiqueta de cierre de un elernento en el periodo de ejecuci6n. Su valor de retorno puede ser EVAL-PAGE o SKIP-PAGE. EVAL-PAGE hari que la rniquina JSP evalfie el resto de la pigina, SKIP-PAGE, la evahaci6n de la pigina. El valor de retorno SKI P-PAGE s610 debe ser utilizado con una buena raz6n puesto que 10s rnanejadores de etiqueta para concluir la evaluaci6n de la pigina pueden ser confusos y norrnalrnente habri una forrna rnejor de irnplernentar la funcionalidad requerida. U n uso legitirno podria ser concluir la salida de la pigina si esti establecido que el usuario no tiene suficientes privilegios para ver la totalidad de la pigina.

Hay tarnbikn una serie de rnktodos relacionados con la anidacibn, la inicializaci6n y la reutilizaci6n de etiquetas: \
Tag getparent 0 void setparent 0

La especificaci6n tarnbikn requiere rnktodos para exponer la propiedad parent. U n progenitor de etiquet es la etiqueta que lo incluye directarnente en una JSP. Las irnplernentaciones de etiqueta pueden consultar sus progenitores en el periodo de ejecuci6n, para obtener inforrnaci6n de contexto:

Capitulo 11
void setpagecontext
()

(Pagecontext pc)

setpagecontext la etiqueta.
void

es un rnetodo de inicializacidn que pone P a g e c o n t e x t de la JSP a disposicidn de

release 0

r e l e a s e ( ) es invocado para el rnanejador de etiqueta libere cualquier recurso, quizis para cerrar una conexidn JDBC o abrir un socket requerido por el manejador para su funcidn. La irnplernentacidn de la metodo r e l e a s e ( ) no debe asurnir nada sobre el estado de las propiedades del rnanejador de etiqueta; la especificacidn establece que, cuando r e l e a s e ( ) es invocado, todas las propiedades habrin sido reiniciadas en un valor n o especificado. El API tarnbien proporciona una clase T a g s u p p o r t que irnplernente la interfaz T a g y proporcione mktodos vacios por defect0 para 10s rnetodos definidos.

La interfaz javax.servlet.jsp.tagext.lterationTag
La interfaz 1 t e r a t i o n T a g ha sido afiadida a JSP 1.2 y arnplia la interfaz Tag. Proporciona un unico mitodo que perrnite a la etiqueta repetir la evaluacidn del contenido del cuerpo de la etiqueta:
int doAf terBody ( ) throws JspException

d o A f t e r B o d y ( ) es invocado cada vez que el cuerpo de la etiqueta ha sido procesado (donde se hubiera invocado d o E n d T a g ( ) en el caso de una irnplernentacidn de la interfaz Tag). Los valores de retorno vilidos de d o A f t e r B o d y ( ) son EVAL-BODY-AGAIN y SKI P-BODY. U n valor de retorno de EVAL-BODY-AGAIN dirige la rniquina JSP a evaluar el cuerpo de la etiqueta y cualquier etiqueta descendiente de nuevo, teniendo corno resultado a1 rnenos una llamada rnis a este metodo. U n valor de retorno de S K I P-BODY provoca la finalizacidn del procesarniento del contenido del cuerpo, que puede ser utilizado para ciclar condicionalrnente el contenido de la etiqueta. En JSP 1.1, era necesario u t i k a r la interfaz BodyTag para ejecutar la iteracidn. La introducci6n de la interfaz I t e r a t i o n T a g (mucho rnis sencilla) es una buena noticia, puesto que la interfaz BodyTag presenta complejidades innecesarias de constructores de ciclado sencillos.

La interfaz javax.servlet.jsp.tagextsodyTag
BodyTag ampha I t e r a t i o n T a g , afiadiendo retrollarnadas y otros rnetodos extra y permitiendo a1 prograrnador trabajar con el contenido del cuerpo de la etiqueta. En JSP 1.1, BodyTagarnpliabaTag. Sin embargo, el carnbio es de retroactividad compatible ya que el rnktodo doAfterBody0 ha sido sirnplemente trasladado desde BodyTaga la nueva interfaz IterationTag.
\

U n diagrama de secuencias que rnuestre la interaccidn entre JPS llarnante y el manejador de etiqueta en el caso de una etiqueta de cuerpo es rnucho rnis cornplejo que el de la interfaz Tag:

Extensiones de etiaueta JSP

m
Etiaueta

Los pasos adicionales (en comparaci6n con la invocaci6n de la interfaz Tag) conllevan la presemaci6n de J S PWri t e r de la pigina JSP (mensajes 5 y 10) y la posibilidad de llamadas repetidas a1 metodo doAf t e r B o d y ( ) , que capacita a la implementaci6n BodyTag para tomar el control de la ejecuci6n de la etiqueta en el period0 de ejecuci6n. Algunos de 10s metodos heredados de la interfaz BodyTag utilizan diferentes valores de retorno para sostener su mayor funcionalidad. Lo siguiente es un anilisis de 10s mitodos mis importantes, tanto 10s nuevos como 10s que tienen una funcionalidad mejorada:
int doStartTag 0 throws JspException

Capitulo 11
Este mktodo es invocado cuando se encuentra la etiqueta de inicio, para las interfaces de etiqueta mis sencillas. Sin embargo, el significado de 10s valores de retorno difiere. Tres valores de retorno aparecen en que tiene el JSP 1.2: SKIP-BODY, que cuyo caso el contenido del cuerpo sera ignorado; EVAL-BODY, mismo sipificado que el I t e r a t i o n T a g ; y EVAL-BOY-BUFFERED. La devolucibn de EVAL-BODY-BUFFERED provoca que el objeto B o d y C o n t e n t sea creado para i n c h en blifer 10s resultados de la evaluaci6n del cuerpo y sostener la posterior manipulaci6n por parte del manejador de etiqueta. Si se devuelve EVAL-BODY-BUFFERED, el des rrollador es responsable de producir el contenido del cuerpo, probablemente en el m k t o d o d o ~ n d ~ ( a)g . aposibilidad de usar el blifer d e ~ o d y ~ o n t e n t es la que permite a BodyTag transformar o suprimir el contenido del cuerpo.

En JSP 1.1, el tinico modo de evaluar el contenido del cuerpo era medtante la ya obsoleta constante EVAL-BODY- TAG. Este ten ia el mismo efecto que la nueva constante EVAL-BODY-BUFFERED. En d ~ como It e r a t i o n Tag: el desarrollador siempre JSP I . I , no era posible que ~ o ~agfuncionara tenia que producir el contenido del cuerpo en el mktodo doEnd Tag 0.
v o i d setBodyContent (Bodycontent bodycontent)

Este mktodo de inicializaci6n es utilizado para configurar el objeto utilizado para manipular el contenido del objeto. Solo es invocado s i d o s t a r t ~ a (g) ha devueltoE~AL-BODY-BUFFERED.
i n t doInitBody ( ) throws J s p E x c e p t i o n
()

Al igual qu-e s e t B o d y C o n t e n t devuelto EVAL-BODY-BUFFERED.

, este metodo es invocado por la miquina JSP solo si d o S t a r t T a g ha En este caso, es invocado despuks de s e t ~ o d y ~ oe n nt ( ) .
JspException

i n t d o A f t e r B o d y ( ) throws

Este metodo es heredado de la interfaz I t e r a t i o n T a g y fucniona del mismo modo. En cuanto a I t e r a t i o n T a g s , 10s valores vilidos de retorno son EVAL-BODY-AGAIN y SKIP-BODY.

La clase javax.servlet.jsp.tagextB0dyContent
La clase B o d y C o n t e n t es clave de la funcionalidad d e ~ o d y ~ buferizado. ag B o d y C o n t e n t es una subclase de JspWr i t e r que puede ser utilizada para manipular el contenido del cuerpo de las implementaciones de BodyTag y almacenarlas para su posterior recuperacion. El mktodo devuelve ~ ~ o ru t n a i n s t a n c i a ~ o d y ~ o n t e asociadaauna nt g e t BodyContent ( ) d e ~ o d y ~ a g ~ u etiqueta concreta. Para comprender c6mo funciona la clase B o d y C o n t e n t , considere como son manejados 10s objetos JspWr i t e r en piginas JSP que utilizan BodyTags (mensajes 5 y 10 del anterior diagrama de secuencias). Antes de que BodyTag comience a evaluar su contenido de cuerpo, la clase de implementaci6n generada incluye la siguiente linea:
out
=

pageContext . pushBody

( ) ;

Despues de que 10s mktodos de BodyTag hayan sido invocados, incluye una llamada correspondiente:
out
=

pageContext.popBody( i ;

Esto significa que cada BodyTag es capaz de manipular su B o d y C o n t e n t sin afectar automiticamente el JspWr i t e r de la pigina JSP incluida (o etiqueta). Para generar informaci6n, el BodyTag necesita escribir 10s contenidos de su B o d y C o n t e n t explicitamente en su escritor adjunto (vkase mis adelante). Esta es la diferencia clave entre ]as implementaciones BodyTag y Tag. Las implementaciones T a g no tienen tanta flexibilidad y, por lo tanto, no pueden modificar o suprimir su contenido de cuerpo. Pueden, sin embargo,

Extensiones de etiaueta JSP


evitar que sea evaluado del todo por el valor de retorno SKIP-BODY en la implementaci6n de d o S t a r t T a g 0. Los metodos mas interesantes de la clase B o d y C o n t e n t son:
void clearBody ( )

Este metodo limpia el contenido del cuerpo; es fitil si ueremos manipular el contenido del cuerpo antes de 9 escribirlo.
JspWriter getEnclosingWriter0

Este m6todo devuelve el JspWr i t e r incluido, que puede ser el escritor de una etiqueta incluida, o el escritor de una pigina JSP. Habitualmente utilizamos este metodo para obtener un JspWr i t e r en el que podamos escribir el contenido del cuerpo almacenado en una etiqueta de cuerpo cuando hayamos terminado de manipularlo. Por ejemplo, podriamos utilizar las siguientes lineas de c6digo en el metodo doEndTag ( ) de una subclase de BodyTag para obtener el contenido del cuerpo de la etiqueta y producirlo (en este caso, sin modificar):
BsdyConter~t bodyContertt = getBodyCorttent [ J ; i f (bodycontent ! = null) {

bodyConter~t.getEnclosir~gWriter~).write(sbOut.toStrir~g() );
1

Este metodo asegura que ni hay cualquier contenido de cuerpo albergado en la etiqueta, sera escrito al escritor JSP incluido.
String getstring()

Este metodo devuelve el contenido ya albergado en el objeto B o d y C o n t e n t , como un S t r i n g . Podemos invocarlo en cualquier metodo de retrollamada para conocer 10s resultados cumulativos de evaluaci6n. La ( )d nos ~ invocaci6n de g e t s t r i n g ( ) seguido de c l e a r ~ o d (y) en la r e t r o l l a m a d a d o ~ f t e r ~ o permite examinar, sucesivamente, el resultado de cada evaluaci6n del contenido del cuerpo de la etiqueta.

Clases de conveniencia
Algunos de 10s mktodos Tag, I t e r a t i o n T a g y BodyTag serin implementados de mismo mod0 en la mayoria deetiquetas,porloqueelpaquete j a v a x s e r v l e t . j s p . t a g t e x t incluyedos implementaciones de convenienciapara~ag y BodyTag: T a g s u p p o r t y s u subclaseBodyTagSupport. Las clases que implementan las extensiones de etiqueta derivarin normalmente de una de 6stas. Este diagrama de clases muestra la relaci6n entre estas clases y ]as interfaces T a g y BodyTag:

Capitulo 11

interfaz

interfaz

interfaz

Tag

CteratimTag
+doAfterBom:int

~ o dTag y
+dolnitSodyO:~nt

J
TagSupport +findAncestoMnClassO:Tag

I
BodyTagSupport

previous0ut:JspWriter
bodyContent:BodyContent

Las clases T a g s u p p o r t y B o d y T a g S u p p o r t son concretas, rnis que abstractas. Corno tales, proporcionan irnplernentaciones cornpletas de las interfaces correspondientes. Estas irnplementaciones no realizan ninguna funci6n except0 devolver 10s valores apropiados que perrniten a la rniquina JSP continuar representando la pigina. Por ello 10s desarrolladores pueden ornitir con seguridad 10s rnetodos en 10s que no estin interesados. Por ejernplo, 10s desarrolladores no se preocupan con frecuencia de rnanejar la propiedad parent y del rnetodo s e t p a g e c o n t e x t ( ) . El metodo r e l e a s e ( ) tarnbien puede ser ornitido si no es precis0 liberar recursos. Los rnktodos que un desarrollador querri ignorar ( )ypara normalrnente s o n d o S t a r t T a g ( ) y doEndTag ( ) para todas las e t i q u e t a s ; d o ~ f t e r ~ o d I t e r a t i o n T a g s yBodyTags; y d o I n i t B o d y ( ) paraBodyTags. T a g S u p p o r t tarnbien pone a disposici6n de las subclases una importante variable de conveniencia: p a g e c o n t e x t (la variable p a g e c o n t e x t guardada y configurada por la rniquina JSP cuando la etiqueta ( )gde B o d y S u p p o r t T a g devuelve fue utilizada en unapigina por prirnera vez). El r n e t o d o d o ~ t a r t ~ a EVAL-BODY-BUFFERED y produce el rnismo rendirniento que B o d y T a g S u p p o r t ofrecido en JSP 1.1, capturando autorniticarnente la salida en un objetoBodyContent. B o d y T a g S u p p o r t proporciona un metodo g e t B o d y C o n t e n t ( ) ,posibilitando la obtenci6n de contenido bufferizado y su rnanipulaci6n. N o hay implernentaci6n de conveniencia en la interfaz I t e r a t i o n T a g , ya que s61o afiade un rnetodo nuevo a Tag, doAf t e r B o d y ( ) ,que siernpre necesita ser irnplernentado por el desarrollador de etiqueta. Sin embargo, la clase ~ a g ~ u p p opuede r t ser utilizada corno la superclase de 1t e r a t i o n T a g .

Objetos de disposicion de 10s manejadores de e'tiqueta


Todos 10s manejadores de etiqueta tienen acceso automitico a rnis informaci6n de contenido que la disponible para 10s JavaBeans utilizados en todas las piginas JSP. Esta informaci6n esti disponible a traves de 10s manejadores de etiqueta del objeto P a g e c o n t e x t que son pasados en la inicializaci6n. Corno recordari, j a v a x .s e r v l e t .j s p . P a g e c o n t e x t es una carpeta adecuada para inforrnaci6n sobre el period0 de ejecucidn de una pigina JSP, incluido 10s objetos r e q u e s t y r e s p o n s e y referencias a objetos corno beans utilizados por la pigina JSP. Esta cantidad de acceso es igual a capacidad. Observe, sin embargo, que denota rnuy poco estilo rnodificar objetos solicitud y respuesta directarnente desde un rnanejador de etiqueta. Las etiquetas personalizadas deben ser consideradas corno bloques de construcci6n destinados a ser utilizados en una arnplia variedad

Extensiones de etiqueta JSP


de contextos y no deben verse afectados por 10s parirnetros pasados a la pigina JSP. Aunque un rnanejador de etiquetapuede acceder a 10s parirnetros de solicitud, confiar en ello reduciri arnpliarnente su capacidad de reutilizaci6n.

Revision del sencillo ejemplo


Para recuperarnos despues de tanta teoria, vearnos de nuevo la irnplernentaci6n Java del sencillo ejernplo que hernos presentado anteriorrnente. Vernos que el rnanejador de etiqueta arnplia Tagsupport y asi obtiene la mayor parte de su funcionalidad ya irnplernentada. N o tiene estado ni accede a ningun archivo u otros recursos, por lo que no hay necesidad de ignorar el rnttodo release ( ) . Sirnplernente utilizarnos doEndTag ( ) paraacceder apagecontext, obtener JspWriter y generar salida:
package import import import import publlc tagext; j a v a . i o . IOExceptiori; java . u t i l . Date; j a v a x . s e r v l e t . j s p . *; j avax. s e r v l e t . j sp. taqext clas? HelloTag exterda

.TaqSupport;
{

TagSuppiirt

Este metodo sera invocado cuando la rniquina JSP encuentre el inicio de la etiqueta irnplernentada por esta clase. Devuelve un valor que indica si evaluar o no cualquier contenido de cuerpo que puede tener esta etiqueta. Los valores legales de retorno son EVAL-BODY-INCLUDE (destinado a evaluar el contenido de cuerpo de la etiqueta y cualquier sub-etiqueta) y SKI P-BODY (que significa que 10s contenidos de la etiqueta serin ignorados) .
public i n t d o S t a r t T a g ( ) throws r e t u r n EVAIjpBODY-INCLUDE; JspTagException
[

I Este rnetodo seri invocado cuando la rnaquina JSP encuentre el cierre de la etiqueta irnplernentada por esta clase. Devuelve un valor que indica si debe evaluar o no el resto de la JSP. Los valores legales de retorno son EVAL-PAGE (el caso habitual) y SKIP-PAGE.
p u b l i c i r j t doEridTag ( ) t h r o w s J s p T a g E x c e p t i o r l { S t r i r l g d a t e S t r i r l q = new D a t e ( ) . t o s t r i n g ( ) ; try { / / Obter~er e l JspWriter a c t u a l d e l corltexto d e l a e t i q ~ ~ e t a // y escribirle paqeCorltext . g e t o u t ( ) . w r i t e ( " H e l l o world. < b r / > " ] ; p a g e C o r ~ t e x. t g e t o u t ( ) . w r i t e ("My r~ame i s " t g e t c l a s s ( ) . g e t N a m e " and i t ' s " t d a t e S t r i r q + " < p / > " 1 c a t c h (IOException e x ) [ t h r o w r~ew J s p T a g E x c e p t i o r l ( " F a t a l e r r o r : h e l l o t a g c o u l d rlot w r i t e t o JSP o u t "

I
return EVAL-PAGE;

Fijese en que necesitarnos cornprobar IOExcept ions a1 generar inforrnaci6n de salida. Cualquier excepci6n encontrada durante el procesarniento de la etiqueta debe ser envuelta corno JspException si debe ser lanzada de nuevo. Es una buena prictica utilizar la subclase javax. servlet. jsp. ~ s ~ ~ a ~ ~ x c e ~ t i o n d e ~ s ~ ~ (Observeque,deforrnaconfusa,tste xception. no esti en el rnisrno paquete que las otras clases especificadas a 10s rnanejadores de etiqueta.)

Capitulo 11
En realidad, podriarnos haber ornitido el metodo d o S t a r t T a g ( ) . Lo incluirnos para una mayor integridad pero, de hecho, hace exactarnente lo que rnisrno que hace el rnetodo d o S t a r t T a g ( ) de su superclase T a g s u p p o r t ; instruye a la mlquina JSP para evaluar el contenido de la etiqueta y de cualquier sub-etiqueta y podria utilizarse para confiprar cualquier recurso que necesitara la etiqueta, corno abrir una conexion a una base de datos.

Descriptores de biblioteca de etiqueta


U n descriptor de biblioteca de etiqueta, Tag Library Descriptor (TLD), es un docurnento XML con una extensi6n t l d que describe una o rnis extensiones de etiqueta.

H a y muchas ventajas en el uso de notaciones X M L para T L D , asi corno para otros descriptores de despliegue de J 2 E E . Los documentos X M L son fa'ciles de componer para las herramientas y faciles de validar. Sin embargo, debido a que X M L es de base textual, son tambie'n fa'ciles de editar rnanualmente. Resulta tambie'n m u y fa'cil extraer informacio'n de u n documento X M L ya que esta' pefectamente estructurado. Por ejemplo, una hoja de estilo X S L T p o d r i a utilizarse facilmente para producir docurnentacio'n legible para u n L D T .

Una biblioteca de etiquetas nos perrnite agrupar etiquetas con funcionalidad similar proporcionando extensiones de etiqueta y relacionindolas con clases Java. Los TLD deben ajustarse a una de las dos Definiciones de Tipo de Docurnento (DTD) incluidas en la especificaci6n JSP 1.2. rnuchos de 10s elernentos de la biblioteca de etiquetas pretenden principalrnente proporcionar apoyo a las herrarnientas de cornposici6n de JSP, por lo que s61o exarninarernos las que resultan esenciales para 10s desarrolladores. Antes de probar estas etiquetas, debe asegurarse de que su contenedor se ajusta a ellas.
Esta seccio'n hace referencia a1 DTD de la biblioteca de etiqueta inchid? en la especifi:caci6n J S P 1.2, disponible en http:lljava.sun.comldtdlWeb-jsptag/ibrary_l2.dtd. Esta difi:ere de la incluida en la especifi:cacio'nJ S P 1.1. ( L a mayoria de las diferencias son menores, como la adicidn de u n guidn en rnuchos nombres de elemento, aunque J S P 1.2 aiiade tambie'n algunos elernentos nuevos.) Los contenedores que cumplen con J S P 1.2 deben aceptar bibliotecas de etiqueta que se adapten a1 D T D de J S P 1.1, para asegurar la retroactividad compatible. El D T D de J S P 1.1 esta' disponible en http:// java.sun.comlj2ee/dtdslWeb-jsptaglibraryry11l.dtd. Puede remitirse a 10s comentarios de ese docuemnto para mantener las bibliotecas de etiquetas J S P 1.1.

El elernento raiz es < t a g l i b > ,definido en el D T D por:


<!ELEMENT taglib (tlib-version, jsp-version?, short-name, uri?, display-name?, small-icon?, large-icon?, description?, validator?, listener*, tag+) > 0

t 1i b - v e r s i on es la versi6n de la irnplernentaci6n de la biblioteca de etiqueta y es definida por el autor de la biblioteca de etiqueta. La versi6n debe ser especificada en forrna decimal. Ejernplos de versiones vdidas: 0.7 y 1.12.
j s p - v e r s i o n es laversi6n de la especificacidn JSP de la que depende la biblioteca de etiqueta. Actualrnente, el valor a utilizar es 1.2 (por defecto), a rnenos que este trabajando con un contenedor JSP que s61o se ajuste a JSP 1.1, en cuyo caso necesitarl especificar 1.1.Este elernento es opcional.

s h o r t -name es un simple nornbre por defecto que podria ser utilizado por una herrarnienta de

cornposici6n JSP. El rnejor valor a utilizar es el valor de prefijo preferido: es decir, una sugerencia de prefijo a utilizar a1 irnportar la biblioteca de etiqueta. Aunque no hay rnodo de ejecutar esto, esperarnos que 10s desarrolladores que utilicen la biblioteca hagan caso de esta sugerencia y se

Extensiones de etiaueta JSP


alcanzari un nivel de consistencia entre todos 10s usuarios de la biblioteca de etiquetas. El s h o r t n a m e no debe contener espacios en blanco o empezar por un digito o subrayado. d e s c r i p t i o n es una cadena de texto arbitraria que describe la biblioteca de etiquetas. Imaginela corno el equivalente de un docurnento Javadoc relacionado con una clase o paquete completo; la herramienta de composici6n puede mostrarla cuando la biblioteca de etiqueta sea irnportada.
0

v a l i d a t o r es un sub-elernento introducido en JSP 1.2. Puede ser utilizado para especificar una clase Java que puede utilizarse durante el periodo de traducci6n paravalidar el uso de las etiquetas en la biblioteca de etiquetas. La validacion es ejecutada en forrna XML de piginas JSP en la biblioteca deetiquetas. l i s t e n e r es un sub-elernento introducido en JSP 1.2. Integra bibliotecas de etiquetas con el apoyo para eventos de nivel de aplicacion introducidos en el API Senlet 2.3. Estudiarernos este elemento rnis tarde, en este capitulo.

El elernento < t a g > es el rnis importante. Esti definido en el D T D corno: <!ELEMENT tag (name, tag-class, tei-class?, body-content?, display-name?,
small-icon?, large-icon?, description?, variable*, attribute*, example?)

>

name es el nornbre que identificari estaetiqueta (desputs delprefijo de biblioteca de etiqueta). t a g - c l a s s es el nornbre completo cualificado de la clase de manejador de etiqueta que irnplementa estaetiqueta. Estaclasedebeirnplementarlainterfaz j a v a x s e r v l e t .j s p . t a g e x t . T a g (obviamente, puede implementar una de ]as subclases I t e r a t i o n T a g o B o d y ~ a g ) .

tei-classdefineunasubclasedejavax. s e r v l e t .j s p . t a g e x t .TagExtraInfoque proporcionari informaci6n extra sobre esta etiqueta en el periodo de ejecuci6n a la pigina JSP. N o ~nf todas ]as etiquetas requieren una c l a s e ~ a g ~ x t r ao. b o d y - c o n t e n t es un atributo opcional que especifica el tipo de contenido de cuerpo quedebe tener la etiqueta. Hay tres valores legales: t a g d e p e n d e n t , J S P y empty. El valor por defect0 (y el mis util) es JSP, que significa que el contenido de cuerpo de la etiqueta sera evaluado en el periodo de ejecuci6n igual que cualquier otro contenido JSP. t a g d e p e n d e n t significa que la miquina JSP no debe intentar evaluar el contenido pero debe aceptar que, aunque quizis no lo entienda, tiene algun significado para el manejador de etiqueta y debe, por lo tanto, ser pasado sin modificar. e m p t y resulta util cuando una etiqueta no debe tener ningun contenido de cuerpo. Si se utiliza este valor y la etiqueta no esti vacia, la traducci6n JSP fallari. Las s u b - e t i q u e t a s v a r i a b l e s son utilizadas para indicar que una etiqueta declaravariables de directiva disponibles para las piginas JSP que las utilizan. Esta es una funci6n irnportante, que examinaremos con mis detalle posteriormente. El sub-elemento optional < e x a m p l e > del elemento < t a g > es una adici6n de JSP 1.2 y proporciona una descripci6n informal del uso de la etiqueta. A1 utilizar este elemento, recuerde evitar 10s caracteres < y > para asegurar que el TLD sigue siendo un docurnento XML de forma correcta. Los contenidos del elernento e x a m p l e podrian ser rnostrados por una herrarnienta de composici6n para proporcionar informaci6n Gtil para ayudar a 10s desarrolladores JSP que la utilizan.

Las sub-etiquetas < a t t r i b u t e > de un elemento< t a g > describen cada atributo aceptado (o requerido) por la etiqueta. La definici6n D T D es la siguiente: <!ELEMENT attribute
(name, required?, rtexprvalue?)

>

Capitulo 11
0 name es el nornbre de este atributo, corno apareceri en las piginas JSP que utilicen la etiqueta. 0 required especifica si este atributo es o no obligatorio. Los valores vilidos son true (el atributo es requerido) y f alse (por defecto, indicando un atributo opcional). El atributo puede tener un valor por defecto. 0 rtexprvalue especifica si el valor del atributo puede o no ser el resultado de una expresidn JSP, o si tiene una valor fijo en el periodo de traduccidn cuando la etiqueta es utilizada en una pigina JSP. Los valores vilidos son true y false.El valor por defecto es false,que significa que la prohibici6n de las expresiones. Si el valor de rtextprvalue es true,el siguiente c6digo JSP es legal:

Perrnitir a 10s atributos tornar valores de expresion puede ser rnuy util, ya que perrnite que su funcionarniento sea deterrninado en el periodo de ejecucion. Por qjernplo, 10s atributos de etiqueta serin configurados a rnenudo en el valor de propiedades de beans JSP. Este confia en el uso de una expresi6n JSP. La unica ventaja de utilizar un valor false es que garantiza que toda la inforrnacion sobre el uso de la etiqueta (incluido 10s valores de atributo) puede ser puesta a disposici6n de una clase de validation durante el periodo de traduccion. Nuestro TLD de rnuestra era rnuy directo. Corno nuestra etiqueta no torna ningun atributo y no tiene ninguna clase TagExtraInfo asociada, s610 fue preciso un rninirno de elernentos:
<?xml v e r s i i > n = " l . O " er~coding="ISO-8859-1'' ?> < ! DOCTYPE t a q l i b PUBLIC " - / / S u n M i c r o s y s t e m s , I n c . //PTD J S P Tag

Library

1 . 2//ENV

"http://;ava.sur~.com/dtd/Web-jsptaglibrary-l-2.dtd">
<taglib>

<tlib-versinn>l.O</tlib-version>
<j s p - v e r s i " r c > l . 2</ j s p - v e r s i o r c > <short-narne>examples</short-rjame> c:descriptior~>Simple example l i b r a r y < / d e s c r i p t i o r ~ > <tag> <name>hello</r~ame>

<tag-class>tagext.He11oTag</ta4-c1ass> <body-cor~tent>JSP</body-cor~ter,t>
< d e s c r i p t inrj> Simple h e l l o world example. T a k e s no a t t r i b u t e s , a n d s i m p l y g e n e r a t e s HTML/ </description> </tag> </taglib>

Utilizar extensiones de etiqueta en paginas JSP


A diferencia de acciones estindar corno < j sp : forward>,las etiquetas personalizadas deben ser
explicitarnente importadas en piginas JSP antes de poder ser utilizadas, utilizando una directriz t aglib. La sintaxis de esta directriz es la siguiente:
< % @taglib

uri="<uri>" prefix="examples" %>

El atributo uri indica a la rniquina JSP d6nde encontrar el TLD para la biblioteca de etiquetas y el atributo prefix indica a la rniquina JSP quC prefijo sera otorgado alas etiquetas de esta biblioteca en el resto de la pagina JSP.

Extensiones de etiqueta JSP


Una pigina JSP puede irnportar cualquier nfirnero de bibliotecas de etiqueta. La directriz t a g l i b provocari una excepci6n en el period0 de traducci6n si la biblioteca de etiquetas no puede ser localizada, rnientras que el primer intento de acceder a cualquier etiqueta definida en el TLD provocari una S e r v l e t E x c e p t i o n en el periodo de ejecuci6n si todas las clase requeridas para apoyar la irnplernentaci6n de la etiqueta puedan ser cargadas. Una vez que la biblioteca ha sido irnportada en la pigina, las etiquetas de la biblioteca pueden ser invocados del siguiente modo:

El rnodo en que las etiquetas personalizadas son utilizadas en piginas JSP es un ejernplo del esfuerzo necesario para introducir convenciones XML en la sintaxis JSP. Observe que, a diferencia de 10s atributos HTML, 10s atributos de etiquetas personalizadas deben estar incluidas entre cornillas sencillas, de acuerdo con la especificaci6n XML. Los prefijos de etiqueta utilizan la rnisrna sintaxis que 10s espacios de nornbre XML. Cuando una etiqueta no requiere contenido de cuerpo, es mejor utilizar la taquigrafia XMLpara que quede explicito:
<exarnples:hello name="Rodn / >

Los prefijos de etiqueta son elegidos en pdginas JSP, no (corno se podria esperar) en bibliotecas de etiquetas. La elecci6n de un prefijo es asunto de 10s desarrolladores pero es deseable que exista consistencia entre pdginas JSP que importen la misma biblioteca de etiquetas. Es mejor adoptar el valor de un elemento shortname de la biblioteca de etiquetas. Los prefijos j sp :,jspx :, javax :,servlet :,sun : y sunw : estdn resewados. Quizds hubiera sido preferible que Sun hubiera definido un sistema exclusivo de nombrado corno el sistema de nombrado del paquete Java para 10s prefijos de biblioteca de etiquetas. Es aconsejable elegir un prefijo exclusivo de una compafiia u organizaci6n: por ejemplo, en lugar de utilizar el nombre corto potencialmente conflictivo tables, seria aconsejable utilizarmy~ompany-tables.

Despliegue y empaquetado de bibliotecas de etiquetas


Existen tres forrnas principales de desplegar y utilizar bibliotecas de etiquetas con una rniquina JSP y debernos farniliarizarnos con todas ellas. Los rnecanisrnos reflejan tres rnodos de asociar atributos u r i utilizados en la directriz t a g l i b a posiciones TLD y son 10s siguientes:
3 Referenciar el descriptor de biblioteca de etiqueta utilizando un elernento de asociaci6n en el

descriptor de despliegue de laaplicaci6n W e b , ~ e bxml. .


0

Ernpaquetar las bibliotecas de etiquetas corno JAR. Esto proporciona el apoyo suficiente para bibliotecas de etiquetas de terceros que estin distribuidas corno caja negra.

0 Tratar el atributo u r i como un verdadero URL, relativo o

absolute, apuntando a un TLD

pfiblicarnente accesible. Exarninernos cada uno de ellos sucesivarnente.

Capitulo 11

Asociaciones en Webaml
En este enfoque de despliegue, el descriptor de la biblioteca de etiquetas, las clases Java requeridas para implementar las etiquetas y las piginas JSP que utilizan la biblioteca de etiquetas estin integradas en un WAR. Este es el enfoque que hemos adoptado en este capitulo. La directriz t a g 1 i b tendri este aspecto:

N o especificamos el verdadero nombre de archivo del TLD, por lo que no es necesario utilizar una extension LTD. El senidor sabe ddnde buscar en el actual WAR de la aplicaci6n Web un archivo . l t d que coincida con este URI porque la asociacion de URI a posici6n de archivo esti especificada en el archivo Web.xml en un elemento < t a g l i b > . El archivo completo web. xml para nuestro sencillo ejemplo seri asi:

\ ! DOCTYFE

Web-app

PUBLIC

'-//Sun

Microsystems, I r ~ c//DTD . Web A p p l i c a t i o r ~ 2. 2//ENi


-

'http://java.~ur~.corn/j2ee/dtds/Web-app 2.2.dtdf>

El e l e m e n t o < t a g l i b > contiene dos s u b - e t i q u e t a s : < t a g l i b - u r i > , que especifica el URI que debe ser utilizado en piginas JSP que deseen utilizar la biblioteca de etiquetas y < t a g l i b - l o c a t i o n > , que especifica la ruta hasta el descriptor de la biblioteca de etiquetas den el WAR. Esta ruta n o necesita estar p6blicamente disponible para usuarios del senidor Web, puesto que el senidor no publicari nada que se encuentre en el directorio WEB- INF. Para comprender c6mo funciona este mecanismo, debemos recordar 10s directorios importantes del WAR:
0 WEB- INF. Contiene el archivo Web.xm1, en el que la asociaci6n de localizaci6n URI TLD debe ser

especificada.
0 WEB- I N F / c l a s s e s . Contiene clases Java requeridas para implementar bibliotecas de etiquetas o,

en su defecto, apoyar la funcionalidad de la aplicacion Web.


0 WEB- I N F / l i b . Contiene archivos JAR que contienen clases adicionales requeridas para apoyar la

funcionalidad de la aplicaci6n Web.


0 WEB- I N F / t l d s . Por convenci6n (aunque no estipulado en ninguna especificaci6n), contiene 10s

descriptores de biblioteca de etiquetas (pero n o las clases manejadoras de etiquetas) que serin puestas a disposici6n de las piginas JSP en el archivo Web. xml. Los TLD podrian en realidad ser situados en cualquier lugar del WAR (siempre que se incluya una asociaci6n en el archivo Web. xml), per0 adaptarse a esta convenci6n facilita la comprensi6n de la estructura del WAR. Utilice este mecanismo para bibliotecas de etiquetas que sean parte de una aplicacidn determinada, en lugar de unidades estindar de despliegue que serin reutilizadas en a l g h otro lugar.

Extensiones de etiaueta JSP

Paquete JAR de biblioteca de etiquetas


Una biblioteca de etiquetas puede ser distribuida en un archivo JARen el que el subdirectorio /META-INF contiene el descriptor de la biblioteca de etiquetas, llamado t a g l i b . l t d . El archivo JAR tambien debe contener las clases necesarias para implementar las etiquetas definidas en la biblioteca de etiquetas pero no contendri ninguna pigina JSP que utilice la biblioteca de etiquetas. En este caso, la directriz t a g l i b en piginas JSP debe referir a este JAR, que probablemente estari en un WAR. Esto permite a las etiquetas personalizadas ser provistos en unidades independientes, una condici6n previa esencial para la distribucih efectiva de etiquetas personalizadas de terceros. La directriz t a g l i b sera asi:

A1 incluir un JAR de biblioteca de etiquetas de este tip0 en una aplicaci6n Web, lo situamos en el directorio /
WEB- INF/, para garantizar que las clases que contiene estarin en la ruta de clase de la aplicaci6n.

Asociacion por defect0


El modo mis ficil de despliegue consiste simplemente en situar el descriptor de biblioteca de etiquetas bajo el documento raiz del servidor (o ponerlo a disposicih de la aplicaci6n como un URL externo) y asegurar que las clases Java requeridas para implementar las etiquetas se encuentran en la ruta de clase de la aplicaci6n. N o se intenta empaquetar una biblioteca de etiquetas o una aplicaci6n. En este caso, la directriz t a g l i b s e d de este modo:

El URI es simplemente una ruta en el servidor host, que puede ser relativa (como en este ejemplo) o absoluta. En este enfoque, el descriptor de biblioteca de etiqueta (aunque no las clases que implementan el manejador de etiqueta) esti siempre pLiblicamente disponible; cualquiera podria verlo con s610 introducirlo en su URL. Es tambiin muy ficil olvidar poner las clases de apoyo a disposici6n de la aplicaci6n. Por estas razones, este enfoque no es recomendable aunque es ficil iniciarse utilizindolo.

Cornbinaciones de asociacion
N o necesitamos obtener del mismo modo todas las bibliotecas de etiquetas que utiliza una aplicaci6n. Es normal combinar el primer0 y el segundo metodo buscando en el archivo Web. xml asociaciones de bibliotecas de etiquetas especificas de la aplicaci6n y buscando dentro de 10s JARempaquetados bibliotecas de etiquetas mis genericas, per0 todos estos enfoques pueden ser combinados en una Linica aplicaci6n.

Escribir extensiones de etiqueta


Una vez asimilados 10s conceptos iniciales, implementar las extensiones de etiqueta es sorprendentemente ficil, asi que pongamos en prktica alguna de esta teoria.

Atributos de procesamiento
Nuestro sencillo ejemplo esti muy bien pero no aprovecha el potencial dinimico de las etiquetas personalizadas. Podriamos interrogar a P a g e c o n t e x t que implementara un funcionamiento especifico

Capitulo 11
del context0 per0 existen alternativas rnis flexibles. (Interrogar a Pagecontext reduciria el grupo de piginas en las que podriamos utilizar la etiqueta.)

El modo m i s ficil de paramctrirar etiquetas en pasar atributos XML.

tC6rno conseguimos que nuestras etiquetas rnanejen atributos? La respuesta es que 10s atributos de un elernento tag LTD se asocian a propiedades bean de 10s correspondientes rnanejadores de etiqueta. La asociaci6n de atributos con propiedades de rnanejador de etiqueta es, corno podriarnos esperar, manejada por la rniquina JSP rnediante reproducci6n. N o s610 funciona con tipos prirnitivos; podemos pasar cualquier tip0 a un manejador de etiqueta. (Las versiones borrador de la especificaci6n JSP 1.1 incluian un sub-elernento tip0 del elemento T L D a tt r ibut e per0 el t ype es detectado en la actualidad utilizando la

reproduction.)
En el LTD se especifica si el atributo es requerido u optional, a1 igual que se especifica si 10s atributos pueden o no tomar el valor de una expresi6n JSP en el periodo de ejecucion. Supongarnos que decidirnos pasar un nornbre corno un atributo. Podernos carnbiar nuestro ejernplo sencillo de rnodo que pueda rnostrar cualquier nornbre que pasemos a la pigina corno parirnetro. En primer lugar, necesitamos escribir un manejador de etiqueta con una propiedad name. Con este minirno carnbio, se parece rnucho a HelloTag. Las lineas nuevas o rnodificadas aparecen destacadas:
package import import import import tagext; java.in.1OException; j a v a . u t i l . Date; j a v a x . s e r v l e t . j s p . '; javas. s e r v l e t . j s p . tagext .*; extends Tagsupport
{

public c l a s s AttribHelloTag p r i v a t e S t r i n g name; I p u b l i c S t r i n g getNamei r e t u r n name;

I
public void t h i s . name
=

s e t N a m e ( S t r i n g name) name;

I
p u b l i c i n t doStartTag ( ) throws r e t u r n EVAL BODY INCLUDE; JspTagException

I
p u b l i c i r l t doEndTag ( ) t h r o w s J s p T a g E x c e p t i o n { S t r i n g d a t e s t r i n g = new D a t e ( ) . t o s t r i n g ( ) ; try [ p a g e c o n t e x t . g e t o u t ( ) . w r i t e ( " H e l l o < b > " t getName ( ) t p a g e C o n t e x t . g e t o u t ( ) . w r i t e ("My name i s " t g e t c l a s s ( ) " and i t ' s " t d a t e s t r i n g ] cacch (IOException e x ) { t h r o w new J s p T a g E x c e p t i o n ( " H e l 1 o t a g c o u l d n o t w r i t e

"</b>.<br/>"); .getName ( ) t t "<p/>"); to JSP o u t " ) ;

I
return EVAL-PAGE;

I
Guarde este archivo de clase e n W E B - I N F / c l a s s e s / t a g e x t . N o se sienta tentado a ornitir el rnetodo para la obtencion de propiedad ge tName ( ) , que a prirnera vista puede parecer innecesario, ya que podriamos sirnplernente acceder a la variable de instancia de nornbre despuks de haber invocado s e t N a m e 0. Algunas rniquinas JSP puede que confien en arnbos rnetodos durante el periodo de

Extensiones de etiqueta JSP


traducci6n y estas propiedades bean deben ser norrnalrnente legibles y escribibles corno una cuesti6n de estilo. Debernos a ~ a d i una r entrada de etiqueta a nuestro LTD que describe la nueva etiqueta y especificar que requiere un atributo,name:
<tag>
<name>helloAttrib</r~ame>

<tag-class>tagext.AttribHelloTag</tag-class> <body-content>JSP</body-content> <description>Simple example with attributes</description> <attribute> <name>name</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag>

El contenedor JSP lanzari una exception si el atributo name requerido es no es especificado y el atributo puede ser configurado con el valor de periodo de ejecuci6n de una expresi6n, asi corno con un string estitico (siendo true el valor de r t e x p r v a l u e ) . Ahora podernos vohernos algo rnis arnbiciosos en el JSP llarnante, h e l l o A t t r i b u t e .j s p . Invocarnos la etiqueta dos veces, para dernostrar el uso de arnbos valores de atributo estitico y de periodo de ejecuci6n. Tarnbikn ofrecernos a1 usuario ayuda en su cavilaci6n por nornbrar la pigina:

<html> <head> <title>Simple tag with </head>

an attribute</title>

<body> <p>This is static output.</p> <p><i><examples:helloAttrib name="Rod"

/></i></p>

Proporcione ahora un valor atributo en el periodo de ejecuci6n:


< % String

readerName

request. getparameter ("reader") ; %>


%>

<P>
< % if

(readerName ! = null) [

Si tenernos un valor con el que podernos trabajar:


Thank you. You told me your name<br / > <i><examples:helloAttrib name="<%=readerName%>" < % 1 else %> /></i>

Si no tenernos un valor con el que trabajar, anirnarnos a1 usuario a facilitar su nornbre:


You're too shy to tell me your name. Try again, using the <b>reader</b> parameter: <br />remember I trusted you with my fully-qualified class name!!
<% ]

%>

</p> <p>This is static output again.</p>

Capitulo 11
La etiqueta puede mostrar ahora cualquier nombre que deseemos. La estructura de su producci6n varia dependiendo de si pasamos o no el parimetro lector utilizado para el valor del atributo de periodo de ejecucibn. Repita 10s pasos que hemos descrito anteriormente para crear y desplegar el WAR, navegue captura de pantalla ilustra 10s entonces hasta http://localhost:8000/tagext/heIloAttribute.jsp. LA siguiente dos casos (fijese en 10s URL). En el primer caso, no se proporcionan parimetros a la pligina:

. . .

, - - ., .

. l
-

I
-

'

o
I
~

I
--- -

.~

-l

.. -

-!I

Archivo

Edk16n Ver

Favortos

Herramlentas
-

9 a, @kqueda -

--

Ayuda

-. .. . . .. .

BFavoritos

H e h Rod My raame is tc~gext.AttnbHelloTagand it k Sat Aug I6 I7:20:59 BS'T2001

III

You're too shy to tell me your name. Try again, using the i enclei parameter: remember I busted you with my My-quaMed class name!!

This is static output again


ist to

I&

II
local manet

Cuando especificamos rln parimetro lector, vemos un valor de atributo de periodo de ejecucibn. Para ver esto en accihn, navegue hasta http://localhost:8000/tagext/hello~ttribute?reader=your~ame:
4 1

, ., . . , 8
I , '

Archwo

Edicion

Ver

Favorites
-

Herramlentas

Ayuda

II

.-

Hello bod. LMS; nanae is tagext.AttribHelloTag ulad dl's Sat Aug 18 17:23:41 BST2001
Thank you. You told me your name Heiio Jack. r M y name is tagext.AttribHelloTag and it's Sat Aug 18 17:23:41 Bfl2001
Thls is static output agah
Listo

r mi
--

v I J -- -

intranet

//

Extensiones de etiqueta JSP


Los atributos son una forma excelente de controlar el funcionamiento de las etiquetas en el period0 de ejecucidn y son especialmente valiosos a la hora de garantizar que las etiquetas son genericas y reutilizables. Por muy elegante que sea el mecanismo de a t r i b ~ t o / ~ r o p i e d a d hay , un problema molesto a1 pasar atributos de string a etiquetas. Especificar ciertos caracteres en atributos es confuso. El caricter de doble comilla, por ejemplo, es ilegal en un atributo y debemos utilizar la referencia de entidad ~ q u o t ; si queremos incluirlas. Esto se vuelve ilegible ripidamente si 10s datos incluyen mGltiples comillas. Los atributos tambien son inadecuados para manejar valores largos, ya que pronto se vuelven ilegibles. Por ello existen limites en cuanto a lo que se puede conseguir de forma sensata con atributos. En lo que se refiere a anotaciones complicadas, considere las alternativas siguientes:
O Procesar anotaci6n y expresiones en el cuerpo de la etiqueta, posiblemente de forma repetida 0 Definir una sub-etiqueta que configure su ascendiente 0

Implementar la etiqueta para leer su anotacidn desde un archivo plantilla o URL

La mis elegante de estas soluciones (aunque no siempre la rnis viable) es manipular el cuerpo de la etiqueta. Esto s61o sera Gtil si la etiqueta define variables de directivas que el cuerpo de la etiqueta puede utilizar.

H a y una incoherencia curiosa y confusa en la sintaxis J S P cuando atributos de etiqueta noS t r i n g son el resultado de expresiones JSP. Supongamos que queremos pasar u n objeto de clase examples. V a l u e s (una especie de lista) a una extensio'n de etiqueta. La sintaxis:

es problemcitica porque sabemos por la especifi:cacidn J S P que una expresidn "es evaluada y el resultado es forzado a u n string que es posteriormente emitido a1 actual objeto o u t JspWri t er". E n el caso de la anterior etiqueta personalizada, sin embargo, el valor de una expresidn no es forzado a u n string sino que pasa el manejador de etiqueta como su tip0 original.

Contenido de cuerpo
Hasta el momento hemos utilizado las etiquetas Gnicamente para anotacidn. N o hemos considerado lo que pueden hacer las etiquetas personalizadas con su contenido de cuerpo (es decir, cualquier elemento entre sus etiquetas de inicio y de cierre). Supongamos que modificamos h e 1 l o . j s p , nuestro primer ejemplo, para afiadir c6digo dentro de uno de las etiquetaes, de este modo:
<examples:hello, T h i s 1s t a g c o n t e n t ! </examples:hello>

Tambikn eliminamos la etiqueta <examp1 e s : h e 11o>. El resultado, guardado en el archivo jt s p , es que el contenido que hemos afiadido es informaci6n de salida ariadida a h e l l o ~ a g ~ o n t e.n cualquier producci6n generada por la etiqueta. Si el contenido aparece antes o despues de la salida de la ( )go etiqueta depende de si decidimos que la salida de etiqueta sea en el m e t o d o d o ~ t a r t ~ a d o E n d T a g ( ) . En el caso de H e l l o T a g , la salida apareceri antes de la propia producci6n de la etiqueta:

Capitulo 11

- -- ..

- -. . -- - - -

Arch~vo Edicltn

Ver

Favorttos

Herramlentas

Ayuda

Thls is static output. Tag output is shown i n itdcs.

This is tag content!Hello world. rMy name is tagext.HelloTag and it's Sat Aug 18 17:28:20 BST2OOI

1
I

T n s is static template data again.


Listo

rr

-1 2
Local intranet

/%

El contenido de la etiqueta sera tratado en el period0 de ejecuci6n como cualquier otro contenido JSP (siernpre que el tip0 de contenido de cuerpo sea configurado en el LTD para ser JSP), por lo que podri incluir expresiones. USP es el tip0 de contenido por defecto.) Intente modificar el liltirno ejernplo de este modo:

Los scriptlets tambiin son legales, como en cualquier otro contenido JS vdlido. El siguiente c6digo producira el rnismo resultado:
<examples: h ~ l l u > C$ i n t a = 37; %> <B i n t h = 1 6 ; %> This t a m 3 c o n t a i n s exprfssiort.? a n d < % = a % > <%=bn> = < 8 = a b 9,-

scriptlets:

<./examples:h e l l o 3

La salida del segundo de estos ejemplos es mostrada e n h e l l o ~ y n a r n i c ~ a q ~ o n t. e jn sp: t

II
I
I&

--

Thls is static output. Tag output is shown in itdcs.

This tag contains expressions and scriptbts: 37 " 16 = 592 Hello world. My name is tagext-HelloTag and it's Sat Aug 18 17:30:23 BST2OO1
Thls is static template data a g h .
ist to

-[

rl
LN~I intranet

Extensiones de etiqueta JSP


Si embargo, para hacer algo realrnente 6til con el contenido del cuerpo, necesitamos conseguir que nuestras etiquetas definan variables de directivas o manipular su contenido de cuerpo.

Variables de directivas introducidas por etiquetas


N o siernpre queremos que las etiquetas produzcan inforrnaci6n ellas rnismas. Puede ser muy Gtil para las etiquetas personalizadas introducir nuevas variables de directivas en la pigina, dejando las piginas JSP llarnantes para controlar la presentaci6n sin ejecutar el procesamiento que conlleva determinar el contenido. JSP 1.1 ofrecio un mod0 de introducir variables de directivas; JSP 1.2 ofrece dos. Esta secci6n analizari el metodo JSP 1.2, que debe ser utilizado en la rnayoria de las nuevas bibliotecas de etiquetas porque es rnis sencillo y rnis intuitivo, antes de analizar el metodo JSP 1.1 (que todavia es aplicado y que ofrece mucha capacidad para etiquetas complejas). Hay dos pasos necesarios para introducir variables de directivas en una etiqueta personalizada en JSP 1.2:
0 0

Ahadauna o rnis sub-etiquetas < v a r i a b l e > a1 elemento relevante < t a g > en elTLD Escriba c6digo para ahadir las variables a P a g e c o n t e x t en el mismo rnanejador de etiqueta

El elemento variable es declarado en el D T D de la biblioteca de etiquetas ask <!ELEMENT v a r i a b l e ((name-given I name-from-attribute), d e c l a r e ? , scope?) > Examinernos sucesivamente cada sub-elemento: variable-class?,

O name-given El nornbre por el que se accederi a la variable de directiva en la JSP. Debe ser un identificador Java legal.
0

name-f r o m - a t t r i b u t e Una alternativa a n a m e - g i v e n , que especifica un atributo cuyo valor deperiodo de traduccidn seri otorgado a la variable. Por ejemplo, si el name-f r o m - a t t r i b u t e tiene el valor "deporteV y la etiquetaes invocadaasi:<mylib : game s p o r t = " t e n i s " / > el manejadorde etiquetapuede crear una variable llarnada "tenis". Dos advertencias: seri re~~onsabilidad del manejador de etiqueta comprobar el valor del atributo relevante para decidir quk nombre otorgar a la nueva variable (vkanse rnis adelante ejemplos de creacidn de variables en manejadores de etiqueta); y 10s valores de period0 de ejecuci6n no estin perrnitidos. Seria ilegal intentar utilizar esta hipotetica etiqueta ask < m y l i b : game s p o r t = " < % s p o r t s B e a n .g e t p r e f e r r e d s p o r t ( ) % > " />.

O variable-class Debe ser el nombre completo cualificado del tip0 de la variable. En la prictica, no seri probado por la miquina JSP en el periodo de traducci6n sino que seri utilizado directarnente en la generacidn de c6digo. Por ejemplo, si j a v a .l a n g . I n t e g e r es especificado para lavariablename, la rniquina JSP generari una declaraci6n corno j a v a . l a n g . I n t e g e r c o u n t ; en representacibn de la clase Java de la pigina JSP. Este elemento es opcional, siendo el valor por defect0 un string.

Observe que la Implementacidn de Referencia (que utiliza Tomcat 4.0 beta 4) maneja este elemento de f o m a incorrecta. Si el elemento es omitido para una variable de tipo java.lang.String, la pdglna JSP no puede ser compilada. Para evitar esto, el elemento opcional siempre debe ser incluido, como hacemos en este capitulo.

Capitulo 11
0

declare Es un parirnetro Booleano que controla si debe crearse una nueva variable o si la etiqueta sirnplernente actualizari el valor de una variable ya existente en P a g e c o n t e x t de la pigina JSP Ilamante. Los valores vilidos con t r u e , f a l s e , y e s y no. Suele ser una buena prictica crear nuevas variables, aunque esto puede provocar un error de period0 de traducci6n si la pigina JSP ya ha utilizado la variable name. Pueden tarnbikn surgir conflictos de nornbre si la misma etiqueta es anidada y 10s descendientes intentan crear nuevas variables con el rnismo nornbre rnientras que una anterior esti todavia en el alcance. Si el valor del parirnetro d e c l a r e es t r u e y va a crearse una nueva variable, la miquina JSP puede generar c6digo Java para declarar una variable del mismo mod0 que un scriptlet puede declarar una variable (en el mitodo -JSP p a g e s e r v i c e ( ) ). En cualquier caso, el JSP obtendri el valor de la variable establecida por el manejador de la etiqueta buscando en P a g e c o n t e x t . Este elemento es opcional con un valor por defecto de t r u e . scope Tres tipos de alcance son definidos para variables introducidas en etiquetas personalizadas: NESTED, AT-BEGIN AT-END. Si el alcance NESTED es especificado, las variables estin disponibles para la JSP llarnante s61o en el cuerpo de la etiqueta determinante. (Permanecerin visibles si otras etiquetas son invocadas en la etiqueta determinante.) Si el a l c a n c e ~ ~ - B E G I N especificado, las variables estarin disponibles para el resto de la JSP llarnante despuks del inicio de la etiqueta determinante. Si el akance AT-END es especificado, las variables estarin disponibles para el resto del JSP llarnante despuks del cierre de la etiqueta determinante. A menos que haya una raz6n de peso para utilizar las variables despuks de que la etiqueta haya sido cerrada, el alcance preferido es NESTED. En piginas JSP, como generalmente en programaci6r-1, las variables adicionales introducen complejidad.

Cambios en el manejador de etiqueta


N o debemos olvidarnos de modificar el manejador de etiqueta. Antes de que estkn disponibles para piginas JSP que utilizan la etiqueta, las variables deben ser afiadidas a P a g e c o n t e x t de este modo:

Ejemplo de variables de directiva


Suponga que hemos decidido que nos gustaria que nuestra e t i q u e t a ~ e l l fuera o rnis configurable. El hecho de que e el lo" y otros textos en inglks estkn refundidos hace que sea muy poco Gtil en otros entornos de lenguaje. Supongamos que decidimos utilizar la etiqueta para proporcionar todos 10s valores dinimicos que hemos visto (nombre, nombre de clase y fecha), per0 controlar la presentaci6n completa en la pigina JSP. Primero creamos una entrada de etiqueta en nuestro TLD que declara el nueva etiqueta, con un subelemento de variable para cada variable de directiva que crea:
<tag> <narne>helloVars</name> <tag-class>tagext.VarHelloTag</tag-class> <body-content>JSP</body-content> <description>Simple example w i t h scripting variables</description> <variable>
<name-given>narne</r~arne-given>

j a va . l a ng . string es la clase por defecto y por ello el siguiente elemento debe realmente ser opcional pero, como hemos visto, la Implementacidn de Referencia genera servlets J S P incorrectos sin ella.

Extensiones de etiqueta JSP


<variable-class>java.lar~g.Strir~g</variable-class> </variable> <variable> <name-given>className</r~ame-given> <variable-class>j ava. larig. S t r i r ~ g < / v a r i a b l e - c l a s s > </variable> <variable> <name-given>date</name-given> <variable-class>java.util.Date</variable-class> </variable> <attribute> <name>name</name>
<required>truei/required>

<rtesprvalue>truei/rte~prva1ue> </attribute> </tag>

Debido a que la mayoria de las sub-etiquetas de < v a r i a b l e > son opcionales y tienen valores por defecto sensatos, estas variables pueden ser declaradas de forma concisa. La variable name es del tip0 por defecto ( j a v a . l a n g .s t r i n g ) y ambas requieren alcance por defecto (NESTED). El manejador de etiqueta es en si mismo muy sencillo per0 se diferencia de 10s que hemos visto hasta ahora en que n o genera anotaci6n. Toda su funci6n es afiadir valores a las variables que acabamos de declarar en e l T L D a P a g e c o n t e x t en su m k t o d o d o s t a r t ( ) . (Cualquier objeto puede ser puesto a disposici6n de una pigina JSP afiaditndolo a1 objeto r e q u e s t , s e s s i o n o a p p l i c a t i o n como atributo. El objeto j a v a x . s e r v l e t . j s p . P a g e c o n t e x t asociado a cada pigina JSP proporciona un ficil acceso a todos 10s espacios de nombre asociados a la pigina JSP.) Puesto que todas estas variables s61o estin disponibles en la etiqueta, seria inGtil afiadirlas al m t t o d o d o E n d T a g ( ) . Sin embargo, si el akance estuviera especificado en AT-END, podrian ser afiadidas en el r n e t o d o d o ~ n d ~0 a g.
package import import import import tagext; j ava. io. IOException; java .util.Date; javax. servlet. j s p . + ; javax.servlet. jsp.tagext.+;
[

public class VarHelloTag extends Tagsupport private String name; public String g e t N a m e 0 return name; 1
[

public void setName (String name) { this.name = name;

public

int doStartTag

( )

throws JspTagEnception

Ponemos las variables a disposici6n de las piginas JSP Ilamantes:


pagecontext. setAttribute ("r~ame",name) ; pageCor~text.setAttribute("c1assName", getClass().getName()) ; pageContext. setAttribute ("date", new Date ( ) ) ; return EVAL BODY INCLUDE;

Capitulo 11

p u b l i c int d o E n d T a g [

throws J s p T a g E x c e p t i a n

N o necesitamos generar anotacion aqui puesto que hemos proporcionado variables que capacitan a las piginas JSP llamantes para generarla por si misma:
r e t u r n E V A L PAGE;

1 La piginaJSP Ilamante, h e l l o w i t h v a r i a b l e s . j s p , puede ahora realizar todo el proceso de representation de la informaci6n de salida:

chtml> <head> < t i t l e > B o n j our: ,:/head>


.'body>

Tag with scripting variables</title>

<p>HTML</p> <p><i> <ei:amples:hellnVars name="Iaabelle"> Bijn j o u r < % = n a m e % > . Je rn'appelle < % = c l a s s N a m s % > .i b r / ; , C'est <%=date%> </examples:helloVars> > +>Plus d e HTML.</pi
</i:p':/r

</body:. :'/htrnl>

La salida en pantalla seri parecidn a la siguiente:

Ver

Favorites

Herramientas

Ayuda

Bonjour Isabelle. Je m bppelle tagext. VarHelloTag. C'est Sat Aug 18 17:36:45 BST2001

Observe que n o necesitamos utilizar las variables de directiva que hemos creado. Los contenidos de la e t i q u e t a < e x a m p l e s :h e l l o V a r s > pueden ser estiticos, en cuyo caso produciria HTML sin modificar, o la etiqueta estaria vacia, en cuyo caso no produciria HTML en absoluto.

Extensiones de etiaueta JSP


Como las variables de directivas introducidas por etiquetas deben ser situadas en Pagecontext por la miquina JSP, solo pueden crearse variables de objeto. Esta es una pequeiia contrariedad cuando lo que prefeririamos en realidad es un tip0 primitivo. Recuerde tambien que aunque nunca se acceda a ellos, 10s valores de todas las variables de descriptivas deben ser computados y situados en Pagecontext.

Definition programatica de variables de directiva


Solo hay un mod0 de definir variables de directiva en JSP 1.1. En lugar de estar definidas en el TLD utilizando el elemento <variable>, las variables han sido definidas en c6digo Java, en el valor de un retorno de metodo. El nuevo metodo, que acabamos de analizar, es rnis sencillo y debe ser elegido en la mayoria de las nuevas bibliotecas de etiquetas. Tambien esti mucho rnis acorde con la filosofia de J2EE preferir la configuraci6n declarativa a la programitica. Sin embargo, el metodo introducido en JSP 1.1 es importante, n o s61o porque es utilizado en la mayoria de las bibliotecas de etiquetas existentes sino porque es algo rnis potente que el metodo declarativo. Esto se debe a que posibilita elecciones complejas a realizar durante la traduccion sobre quk variables exponer y quk nombres otorgarles. Estas elecciones podrian estar basadas en 10s valores de atributos provistos durante el periodo de traduccion. Tres pasos fueron precisos en JSP 1.1 para definir variables de directiva:

O Especificar una clase ~ a g ~ x t r a o ~en nf la entrada de la etiqueta en el TLD. ~ s t es a una clase que proporciona informacion adicional sobre la implementaci6n de una etiqueta durante el periodo de traduccion. O Implementar la clase TagExtraInf o para definir 10s nombres, tipos y alcances de las variables.
0 Definir las variables de directiva en la misma clase de manejador de etiqueta. Este paso es identico al

requerido en el metodo JSP 1.2. Observe que el c6digo del manejador de etiqueta es identico al de la versi6n JSP 1.2. Para ilustrar este proceso, tomemos nuestro ejemplo VarHelloTag y hagamos que defina las mismas variables utilizando una clase TagExtraInfo. (Por cierto, esto demuestra que es posible y en ocasiones btil, tener multiples entradas TLD para la misma clase manejadores de etiqueta.) Analicemos 10s dos primeros pasos. (Podemos saltarnos el tercero, puesto que utilizaremos la misma clase manejadora de etiqueta que en el ejemplo anterior.) En primer lugar, especificamos en el TLD que la clase TagExtraInf o que estamos a punto de escribir estari asociada a esta etiqueta. El elemento etiqueta necesario seri ask
<tag>
<name>helloTEIVars</r~ame>

<tag-class>tagext.VarHellaTag</tag-class> <tei-class>tagext.VarHelloTagE~traIr~fo</tei-c~ass>
<body-content>JSP</body-cor~tertt>

<description>Simple example with scripting v a r i a b l e s < / d e s c r i p t i o r ~ > <attribute> <name>name</ name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag>

Fijese en que no utilizamos ningun elemento <variable>.A continuaci6n, escribimos la clase TagExtraInfo.~ s t debe a derivarse de la clase API JSP javax. servlet.jsp.tagext .TagExtraInfo.~a~~xtra~nfoesunac~aseabstracta,quecontiene cuatro mitodos. Tres de ellos estin relacionados con la validaci6n de biblioteca de etiquetas, que analizaremos rnis tarde. El unico mitodo que nos interesa en este momento tiene la siguiente firma:

Capitulo 11
VariableInfo [ I getVariableInfo (TagData td)

Los datos albergados en la clase V a r i a b l e I n f o deben resultar familiares, puesto que son 10s mismos que 10s especificados en el elemento < v a r i a b l e > TLD que acabamos de examinar. Hay un h i c o constructor, que nos permite especificar todos 10s campos:
VariableInfo(String varName, String className, boolean declare, int scope)

Estos parimetros corresponden a 10s elementos TLD:


0

Nombre de variable (varName). El nombre por el que se accederi a la variable de directiva en la JSP. Debe ser un identificador Java legal. N o m b r e de clase ( c l a s s N a m e ) . Debe ser el nombre cualificado completo del tipo de variable. Declarar ( d e c l a r e ) . Es un parimetro Booleano con el mismo significado que el sub-elemento d e c l a r e delelementovariable.
AT-BEGIN

0 0

Alcance de variable ( s c o p e ) . Tres constantes definidas en la c l a s e v a r i a b l e ~ n o f (NESTED, y AT-END) se corresponden con 10s alcances que ya hemos analizado.

El siguiente listado muestra la irnplementaci6n completa de T a g E x t r a I n f o. Guirdelo como V a r H e l l o E x t r a I n f o .j a v a eneldirectorio habitual: package t a g e r t ; import
javax.servlet.jsp.taqext.*;

p u b l i c c l a s s VarHelloTagExtraInfo

extends TagExtraInfo

N o estamos interesados en el resto de mktodos de esta clase puesto que las implementaciones de no operaci6n ( N O P ) de la superclase realizarin lo siguiente: p u b l i c V a r i a b l e I n f o [ I g e t V a r i a b l e I n f o (TagData d a t a ) r e t u r n new V a r i a b l e I n f o [ I [
{

El uso del akance NESTED significa que estas variables de directiva s61o estarln disponibles dentro de VarHelloTag: new V a r i a b l e I n f o ( " n a m e " , " j a v a . l a n g . S t r i n g W , t r u e , VariableInfo.NESTED), new V a r i a b l e I n f o ( " c l a s s N a m e " , "j a v a . l a n g . S t r i n g " , t r u e , VariableInfo.NESTED), new V a r i a b l e I n f o ( " d a t e " , " j a v a . u t i l . D a t e " , t r u e , V a r i a b l e I n f o . N E S T E D )

I;
1

1
La clase V a r H e l l o T a g E x t r a I n f o seri ahora interrogada por el contenedor JSP durante el period0 de traducci61-1,ya que crea un sewlet a partir de cada JSP que u t i h a ~ a r ~ e l l o ~La ag clase . V a r H e l l o T a g E x t r a I n f o proporciona la misma informaci6n de variable que proporcionaron 10s elementos T L D < v a r i a b l e > en el ejemplo anterior. Cuando utilicemos la nueva etiqueta h e l l o T E I V a r s , 10s resultados serln idknticos a 10s resultados de utilizar la etiqueta h e l l o ~ a r s . Es u n e r r o r mezclar 10s dos m i t o d o s de definici6n de variables de directiva. Si una entrada d e etiqueta e n u n TLD tiene sub-etiquetas<variable>, es err6neo que cualquier clase TagExtraInfo asociada a i l devuelva alglin elemento que n o sea null e n su m i t o d o getVariableInfo ( 1 .

Extensiones de etiaueta JSP

lteracion y rnanipulacion de contenido de cuerpo


Lo que hemos hecho hasta ahora con el contenido de cuerpo y las variables de directiva, utilizando la interfaz Tag, esti muy bien per0 no nos ayuda a hacer nada interesante con el contenido de cuerpo de la etiqueta. iQuk sucede si queremos repetir el contenido de cuerpo un n6mero determinado de veces o si queremos suprimirlo en determinadas circunstancias, o filtrarlo? Para todo ello, necesitamos un API mis complete. iRecuerda las interfaces I t e r a t i o n y BodyTag? Iteration amplia Tag para ajustarse a la evaluacidn repetida de contenido de cuerpo sin transformacidn o supresidn y BodyTag amplia I t e r a t i o n T a g para permitir la manipulaci6n del contenido de cuerpo ademis de la iteracidn.

Evaluacion repetida con la interfaz IterationTag


Uno de 10s usos mis comunes de las etiquetas personalizadas es el manejo de la iteracidn. El flujo de control es manejado de un mod0 mas limpio en las clases Java (corno 10s manejadores de etiqueta) que en las piginas JSP, por lo que situar iteracidn en etiquetas personalizadas puede mejorar notablemente la mantenibilidad de las piginas JSP. Modifiquemos nuestro V a r H e l l o T a g de mod0 que pueda saludar a varias personas a la vez, utilizando la variable name y hagamos que las otras variables de directiva que ya hemos utilizado, className y d a t e , estkn disponibles s61o despuks de que el ciclo de la etiqueta haya sido completado. Necesitaremos cambiar la propiedad que es pasada desde un 6nico s t r i n g (name) a un tip0 indexado; para este ejemplo utilizaremos j a v a . u t i l . L i s t . Tambikn necesitaremos unavariable de instancia para controlar nuestra iteracidn sobre la lista y, por ello, afiadirnos una variable i n d e x para conseguirlo. Para manejar la iteracidn, haremos que nuestra clase de etiqueta implernente 1t e r a t ionTag. Recuerde que 1t e r a t i o n T a g aiiade un 6nico mktodo a la etiqueta:
int doAf t e r B o d y ( )

Este mktodo nos capacita para decidir cada vez despuks de que el contenido de cuerpo de la etiqueta haya sido procesado si continuar o no con el procesamiento, o seguir hasta la etiqueta final. En nuestra nueva c l a s e ~ a r ~ e l l o I t e r a t i o n T ael g, mCtododoAfterBody ( ) devolveri EVAL-BODY-AGAIN hasta que la h a haya sido agotada. Con cada iteracidn, el valor de la variable de nombre es reiniciado. En el periodo de ejecucibn, el contenido de cuerpo de esta etiqueta seri evaluado para cada elemento de la lista, con el valor de la vari,able siempre actualizado:
package import import import import public tagext; j ava. is.IOEzception; java.util.*; javax. s e r v l e t . j s p . +;

javax.servlet.jsp.tagext.*;
class V a r H e l l o I t e r a t l o r ~ T a g e x t e n d s TagSupport implements I t e r a t i o n T a g

Comenzamos con una lista de nornbres pasada:


p r i v a t e L i s t names; p r i v a t e i n t index;

DespuCs producimos lo que estamos construyendo durante la iteraci6n sobre el contenido del cuerpo:
private StringBuf f e r output
=

new

StringBuf f e r ( ) ;

Capitulo 11
Obtener y configurar para la propiedad/atributo de los nornbres:
public List g e t N a m e s 0 return r~ames;
{

1
public void setNames(List names) { this. names = names;

I
public int doStartTag setLoopVariablesi ) ;
( )

throws JspTagException

El valor de retorno es el rnisrno que para una etiqueta normal, no iterativo:


return EVAL BODY INCLUDE;

La rniquina JSP invocari este rnetodo cada vez que el contenido de cuerpo de esta etiqueta haya sido procesado. Si devuelve S K I P-BODY, el contenido de cuerpo habri sido procesado por Gltirna vez. Si devuelve EVAL-BODYAGAIN, el cuerpo sera procesado y este rnttodo seri invocado, como rninirno, una vez rnis:
public int doAfterBody (
)

throws JspTagException

Si todavia no hernos llegado a1 final de la lista, continuarnos procesando:


if (++ir,dex < names.size()) { setLoopVariables( 1 ; return EVAL BODY AGAIN;

Si llegarnos hasta aqui, entonces hernos terrninado de procesar la h a :


return SKIP BODY;

Este metodo es irnplernentado para dirigir la rniquinaJSP para evaluar el resto de la pigina JSP llarnante y exponer las dos variables definidas con alcance AT-END:
public int doEndTag() { pageContext.setAttribute("c1assNarne", getClass().getName()) ; pageContext. setAttribute ("date", new Date ( ) ) ; return EVAL PAGE;

I
Haga a las variables disponibles para cada iteraci6n:
private void setLoopVariables() { pageCor~text.. setAttribute ("name", names. get ( i r d e x ). tostring ( pageContezt. setAttribute ("index", new Integer (irdex)) ;
)
) ) ;

El elemento < t a g > del TLD debe declarar las cuatro variables de directiva. Observe que 10s dos alcances utilizados (NESTED, por defect0 AT-END) para distinpir entre las variables de ciclo y las variables que estarin disponibles despues de que la etiqueta haya sido procesada:

Extensiones de etiqueta JSP


<description>Simple iterative example</description> <variable> <name-given>r~ame</name-giver,> <variable-class>java.lar~g.Strir~q</variable-class> </variable> <variable> <name-given>index</name-given> <variable-class>j ava. lar~g. Integer</variable-class> </variable> <variable> <name-given>className</r~ame-given> <variable-class>java.lar~g.Strir~g</variable-class> <scope>AT END</scope> </variable> <variable> <name-given>date</name-given> <variable-class>java.util.Date</variable-class> <scope>AT END</scope> </variable> <attribute> <name>names</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag>

En la JSP Ilamante, h e l i o I t e r a t o r . j sp, definimos una L i s t a y afiadimos algunos elementos para proporcionar a la etiqueta algo que rnostrar:

Habitualmente, no declaramos variables en piginas JSP (ni irnplementarnos metodos) pero este ejemplo debe ser independiente:
java. util.List r~ames = new j ava.uti1. LinkedList (
) ;

Una JSP puede ignorar este metodo para ejecutar la inicializaci6n. Es anilogo a1 mktodo GenericServlet init ( ) . Este c6digo s61o se ejecutari cuando la pigina JSP sea cargada:
public void jspInit ( ) { names.add("Rod"); ; names .add ("Isabelle") names.add("Bob");

<body> <p>HTML. Output generated using tags is italicized.</p> <p><i> <examples:helloIterator names="<%=names%>"> Hello <b><%=name%></b>. You're er~try <%=index%> in my list.<br/> </examples:helloIterator> </i></p> <p><i>

Capitulo 11
We've f i n i s h e d l o o p i n g , b u t I c a n now a c c e s s t h e </i>cla-csNarne<i> [/%=classNarne%>) and < / i > d a t e < i > ( < % = d a t e % > ) s c r i p t i r s q variables.
</i> <piMore HTML. -/p.>

tag's

</body> ,../htrnl

La salida seri asi:

Archivu
-

EdiciCln

Ver
-

- - -- -

Favontos
-

Herramientas
-

--

Ayuda

HTML Output generated using tags is itdcized.


Hello Rod You %eentry 0 in my Izst. Hello IsubeLLe. You %eentry 1 in my list. Hello Boh. You're entry 2 in my list. Ke Lve$nished looping but 1can now access the tag's classNarne (tagext.VarHelloIteationTa and date (Sat Aug 18 18:06:09 B.53'2001) scripting variables.

'a

ijito

r(I@

Local intranet

#d

Aunque lo hemos desarrollado a partir de nuestros ejemplos anteriores, 6sta es casi una solucion genkrica para la iteraci6n de listas. Oculta el ciclo a la JSP y hace disponibles 10s sucesivos valores y posiciones de h a . Con unos minirnos cambios, esta clase podria tomar una Collection o un ListModel Swing y ponerlo a disposici6n de cualquier pfgina JSP.

La raz6n principal por la que esta etiqueta es tan genkrico es que no genera anotacion. Cuanto mis permita una extensi6n de etiqueta a una pigina JSP llamante controlar su propia producci611, mis htil seri.

Etiquetas de cuerpo que flltran su contenido


Algunas etiquetas necesitan realizar filtrado u otro tip0 de procesamiento en su contenido de cuerpo. Puede ser una sencilla transformaci6n de texto o incluso podria interpretar el contenido de la etiqueta como un lenguaje personalizado. El siguiente ejemplo sencillo toma el contenido de cuerpo de la etiqueta y lo escribe, invertido, en la pagina JSP Ilamante. Para ello, necesitamos utilizar la mis eficaz de las tres interfaces de extension de etiqueta, BodyTag. ~ s t a afiade un nuevo metodo doInitBody ( ) ademis de 10s heredados de la interfaz IterationTag. A diferencia d e ~ a g y s 1 t erat ionTags, BodyTags no necesita producir todo su contenido de cuerpo puesto que ha sido evaluado por la miquina JSP. La clase Bodycontent les permite acceder al contenido de cuerpo a medida que va siendo construido (posiblemente mediante evaluaci6n repetida, controlada del mismo mod0 que por una Iterat ionTag normal). Para utilizar esta funcionalidad mfs capaz, el desarrollador del manejador de etiqueta debe escribir c6digo para producir este contenido de cuerpo

Extensiones de etiqueta JSP


(posiblemente en su forma original, per0 quizis en una forma filtrada o suprimida). Normalmente este c6digo de salida se encuentra en el mCtodo doEndTag ( ) . Recuerde que una etiqueta de cuerpo tiene un objeto JspWriter anidado a si mismo. (Asi es c6mo el contenido de cuerpo puede ser suprimido o manipulado; todavia no ha sido escrito en el JspWriter adjunto.) Esto significa que cuando queramos escribir informaci6n de salida en doEndTag ( ) , necesitamos obtener el objeto JspWriter adjunto. Implementar la inversion es algo trivial; lo unico que necesitamos hacer es obtener el contenido de cuerpo como un String, utilizarlo para inicializar un StringBuf f er e invocar el metodo StringBuf f e r rs reverse ( ) antes de escribir el string resultante:
package import import import public tagext;

ja v a . i o . I O E x c e ~ t i o n ;
javax.servlet.jsp.+; I a v a x . s e r v l e t . js p . t a q e x t class ReverseTag extends

.*;
BodyTagSupport
{

Esti bien que heredemos 10s mCtodos restantes de la superclase BodyTagSupport. Invocada despuks de concluir el procesamiento del contenido de cuerpo, lo utilizamos para obtener el contenido de cuerpo de la etiqueta y escribirlo a1 rev&
p u b l i c i n t doEndTag ( ) t h r o w s J s p T a g E x c e p t i o n { Bodycontent bodyCor~tent = getBodyCuntent ( ) ;

N o haga nada si n o hay contenido de cuerpo:


i f (bodycontent != rcull) { S t r i n g B u f f e r a u t p u t = new S t r i n g B u f f e r ( t , o d y C o n t e n t . g e t s t r i n g ( ) ) ; output. reverse ( ) ; try { bodyCor,tent . g e t E n c l o s i r ~ g W r i t e r ( ) .write (autput.t o S t r i r ~ g ( ) ) ;

I
catch (IOException e x ) i t h r c ~ w new J s p T a g E x c e p t i o r ~ ("Fatal
I0

error"

) ;

I I
Procese el resto de la pigina:
return EVAL PAGE;

La entrada de la biblioteca de etiquetas es tambiCn muy sencilla. N o hay variables ni atributos, por lo que no necesitamos ningbn sub-elementos. El TLD no repara en cuil de las tres interfaces Tag apoya: el contenedor lo estableceri en el period0 de traduccion utilizando la reproduccion.

Una sencilla pigina JSP, reverse. j sp,muestra la etiqueta en funcionamiento:

Capitulo 11

,body>
<i><p> <examples:reverse~ Don't t r y t o p u t HTML m a r k u p i n h e r e : t h e r e s u l t s will b e v e r y i n t e r e s t i n g Hello world i/examples:reverse></p> <p><examples:r e v e r s e Able w a s I e r e I s a w Elba i/exampler:reverse~
</p></1>

/bod yt /htrnll.

Esto produciri la siguiente salida:


---

- -

Archive
C it:.;

Edicih

Ver

Favoritos

Herrarnientas

Ayuda Favoritss ia~ultirnedia t 3

I*

- :a

a ).I

faekqueda
---

1 ~3a i_ 1

draw olleH gnitseretni yrev eb lliw stlrtser eht :ereh ni pukram LMTH tup ot yrt t 'noD
ablE was I ere I saw elbA

El resultado de situar anotaci6n H T M L en el cuerpo de la etiqueta seri impredecible; por lo que la etiqueta se utilizari dos veces para que pueda introducirse alguna anotaci6n d e forrnato entre las instancias d e etiqueta. Existen niuchas aplicaciones htiles pata el filtrado d e etiquetas de cuerpo. Por ejemplo, podriamos ejecutar una transformaci6n XSLT sobre contenido XML.

Anidamiento de etiqueta
Podriamos esperar que la especificaci6n del anidamiento de etiqueta en nuestras etiquetas personalizadas se realizara en el T L D . Sin embargo, 10s T L D no lo permiten y el anidamiento debe ser implementado mediante clases cooperantes de manejador de etiqueta. Afortunadamente, el API nos ayuda en este aspecto proporcionado rnetodos c o n rnanejadores de etiqueta que podemos utilizar para obtener inforrnaci6n sobre sus progenitores y otros ancestros. Aunque 10s prograrnadores de manejadores de etiqueta deben garantizar que llevan a cabo el anidamiento deseado de etiqueta, el descubrimiento dinimico de anidamiento de etiqueta permite una mayor flexibilidad de la que seria posible si el anidamiento fuera

Extensiones de etiaueta JSP


forzado en un archivo estitico. Sin embargo, la ausencia de una gramitica formal, como un esquema de D T D o XML, hace que 10s desarrolladores sean 10s responsables de garantizar que cualquier cooperaci6n entre etiquetas este bien documentada. iPor quk deberiamos utilizar el anidamiento? Una raz6n c o m h es manejar una iteraci6n mis compleja; por ejemplo, las etiquetas anidadas pueden simular ciclos anidados. O t r o uso es dejar que las etiquetas anidadas se beneficien del contexto de la etiqueta o etiquetas adjuntas. Supongamos que tenemos informaci6n adicional que queremos mostrar para las personas enumeradas en nuestra lista pero, como esta informaci6n es costosa de recuperar desde una base de datos o sistema legado, n o queremos que la etiqueta recupere estos campos en cada iteraci6n del ciclo. (Esta necesidad de recuperar con independencia del uso es quizis la 6nica desventaja de utilizar variables de directiva.) Una soluci6n es utilizar una etiqueta descendiente que extrae su contenido de la etiqueta adjunta y ejecuta las b6squedas adicionales s61o cuando es precis0 (es decir, sblo cuando se utiliza la etiqueta descendiente) Implementemos un NameTag que no requiere atributos per0 recupera informaci6n adicional para el usuario que su progenitor esti procesando en ese momento. Esta informaci6n, n a c i o n a l i d a d y c i u d a d , seri expuesta a travks de variables de directiva. Observe que la etiqueta descendiente, igual que cualquier contenido de cuerpo, seri evaluado cada vez que el progenitor itere su contenido de cuerpo. El c6digo JSP que invoca esta funcionalidad puede tener este aspect0 (utilizamos un scriptlet para definir y mostrar la informaci6n extra s61o cuando se desee):
< e x a m p l e s : h e l l o s n a m e s = " < % = n a m e s % > "> H e l l o < % = n a m e % > .You' r e e n t r y < % = i n d e x % > i n my l i s t . <% i f ( c o n d i t i o n ) 1 % > <examples: nameIrlfo> < b > N a t i o n a l i t y : < / b > < % = n a t i o n a l i t y % >< b > C i t y : < / b > < % = c i t y % : < / e x a m p l e s :n a m e I n f o >

<x

%>

<br/> </examples:hellos>

Para implementarlo, primero necesitaremos ahadir un metodo aVarHe 1101 t e r a t i o n que exponga el contexto necesario, S t r i n g getName 0 . Mientras tanto, crearemos una interfaz N a m e c o n t e x t que contengi este nuevo metodo. De este modo, podemos hacer queVarHelloIterationTag, que ya define un m e t o d o g e t ~ a m e ( ) ,implemente la interfaz y proporcione el contexto necesario para nuestras nuevas sub-subetiquetas. La interfaz NameCont e x t es trivial:
package public tagext; irlterf ace Namecontext

Devuelva el nombre expuesto actualmente por este objeto (probablemente una etiqueta adjunta, per0 convirtikndolo en interfaz aseguramos que es una sohci6n general):
S t r i n g qetName ( ) ;

I
La modificaci6n aplicada a V a r H e l l o 1 t e r a t i o n T a g (mis a h de hacerle imp1ementar~amecont ext) es tambien trivial ya que simplemente implementamos un nuevo mktodo:
public S t r i n g getName() { r e t u r n names. g e t ( i n d e x ) t o s t r i n g i ) ;

Exarninernos ahora el nuevo rnanejador de etiqueta NameInf oTag. Sus principales tareas son obtener el contexto a partir de una etiqueta adjunto y recuperar la inforrnacion adicional. Observe corno aplica el anidarniento correcto. Hay un rnktodo g e t p a r e n t ( ) en la interfaz Tag, pero norrnalrnente es preferible utilizar f i n d A n c e s t o r W i t h C l a s s ( ) . Nosotros n o querernos lirnitar el contexto en el que podernos utilizar nuestra etiqueta, ya que no podernos garantizar que otra etiqueta no se sitfie en la jerarquia entre 10s dos etiquetas cooperantes. Si una o rnis etiquetas estin presentes y tenernos confianza de refundido en una deterrninada clase progenitora o interfaz, la etiqueta anidada n o encontrara el ancestro que requiere para proporcionar su contexto. Para una mayor sirnplicidad hernos refundido 10s datos adicionales de la clase, en una tabla hash. Para nuestro ejernplo, irnaginarernos que estos datos son realmente caros de recuperar. La inforrnacion extra sobre las personas de la lista seri la nacionalidad y la ciudad en la que viven en la actualidad:
package tagext;, impcrt import import import j ava. io. IOException; java .util. * ; javax. servlet. j sp. * ; javax.servlet.jsp.tagext.*;
{

public class NameInfoTag extends TagSupport

Cree el alrnackn de datos:


6rivate HashMap infoHash
=

new HashMapi

) ;

Pueble el alrnacin de datos. En una aplicacion real, estos datos proc ederian de una verdadera h e n datos, corno una base de datos:
public NameIr~foTag ( ) { infoHash.put ("Rod", new PersonalInfo ("Australian", "London") ) ; infoHash.put("Isabelle", new PersijnalInfo("French", "Gabon")); infoHash.put ("Bob", new PersonalInfo ("Australian", "Sydney") ) ;
1

public ir4t doStartTag ( ) throws JspTagException { Strlng nationality = "Unknown"; String city = "Unknown";

Cornpruebe si esta etiqueta tiene un ancestro del tip0 requerido, que podarnos utilizar para obtener un nornbre que buscar. Fijese en que utilizar el rnktodo estitico f i n d A n c e s t o r W i t h C l a s s ( ) es rnis flexible que utilizar g e t p a r e n t ( ) . g e t p a r e n t ( ) fallari si uno o rnis etiquetas separan esta etiqueta de la etiqueta deseada en la jerarquia de period0 de ejecucidn de rnanejadores de etiqueta:
NameContext nameContextAncestor = (NameContext) TagSupport. findAncestorWithClass ( this, NameContext.class);

La excepcidn lanzada aqui sera rnanejada por la miquina JSP corno cualquier excepcion lanzada en un scriptletlexpresi6n o corno una excepcion lanzada por un bean. (El resultado probable sera una redireccidn a una pigina de error):
if (nameContextAr~cestor == null) { throw new JspTagException("NameTag must only be used within "a NameContext tag");
"

Extensiones de etiaueta JSP


Si llegamos hasta este punto, tenemos u n ancestro vilido del que podemos obtener u n contexto:
S t r i n g name = r i a r n e C o r l t e x t A r ~ c e s t o r . g e t N a m e( ) ; P e r s o n a l I n f o p1 = ( P e r s o n a l I n f o ) i n f o H a s h . g e t ( n a m e ); i f ( p i != n u l l ) { n a t i o n a l i t y = p i . g e t N a t i o n a l i t y () ; city = pi.getCity();

I
pagecontext . s e t A t t r i b u t e ("r~atior~ality''n , ationality); pagecontext. s e t A t t r i b u t e ("city", c i t y ) ; r e t u r n EVAL B O D Y INCLUDE;
\

Esta clase interna que contiene datos adicionales recuperados para cada nombre es utilizada internamente para posibilitar que dos campos requeridos para cada persona Sean almacenados c o m o un dnico objeto e n una tabla hash:
private private private c l a s s PersonalInfo { S t r i r ~ gr ~ a t i o n a l i t y ; String city; String city)

public Persc?nalInfo(String nationality, this. nationality = nationality; this.city = city;

I
public String getNaticnality return nationality;
( )

1
public String getcity() { return city;

I
TambiCn necesitaremos una nueva entrada en nuestro archivo TLD, recordando utilizar sub-etiquetas de variable para declarar las variables de directiva que crea la nueva etiqueta:
<tag> <name>nameInfo</name>

<tag-class>tagext.NameIr~foTag</tag-class> <body-contentiJSP</body-content>
<description> Tag t o b e n e s t e d w i t h i n a t a g i m p l e m e n t i n g </description> <variable> < n a m e - q i v e r ~ > n a t i o n ailt y < / n a m e - g i v e n > the N a m e C ~ r ~ t e xi tr l t e r f a c e

<variable-class>java.lar~g.Strir~g</variable-class>
</variable> <variable> <name-qiverOcity</name-given> <variable-class>j ava. l a r ~ q .Strir~g</variable-class> </variable> </tag>

Creemos ahora una pigina JSP para utilizar la nueva etiqueta, de m o d o que la bdsqueda adicional sea ejecutada linicamente durante una parte del tiempo. Obviamente, la ldgica de aplicacidn determinari esto normalmente pero, para este ejemplo, simplemente lo decidimos de forma aleatoria. La pigina JSP, hello1 teratorWithNesting . j sp,es muysimilar a1 ejemplo anterior:

Capitulo 11

< %!

java.uti1 .List names

new java.uti1 .LinkedList (

);

public void jspInit() I names. add ("Rod" ; names.add ("Isabelle") ; names. add ("Bob") ; names. add ( " Jens" ) ;
%

>

<body> <p>HTML.</p> <i> < % java.uti1 .Random rand = new j ava.uti1 .Random() ; %> <examples:helloIterator names="<%=names%>" > Hello <%=name%>. You're entry <%=index%> in my list. < % if (rand.nextInt(3) ! = 0 ) { % > <examples : nameInfo> <b>Nationality:</b> <%=nationality%> <b>City:</b> </examples:nameInfo>
<% ] %>

<%=city%>

<br / > </examples:helloIterator> </i> <p>More HTML</p> </body> </html>

Tambikn hemos afiadido una nueva entrada, J e n s , a la lista de nombres, para mostrar quC ocurre cuando no hay informaci6n extra disponible. Manejamos esta situacidn elegantemente, ya que no justifica lanzar una excepcidn que abortaria la representacidn de cualquier JSP que estk utilizando la etiqueta. En su lugar, el valor de reemplazo "Unknown" es situado en P a g e c o n t e x t . Fijese en el uso de un scriptlet en la etiqueta < e x a m p l e s : h e l l o s > para ejecutar la 16gica condicional necesaria. Esto no produce ninguna informac$n de salida y es evaluado cadavez que la etiqueta < e x a m p l e :h e l l o s > procesa su contenido de cuerpo. Unicamente si la condici6n es verdadera (casi aleatorio en este ejemplo), seri evaluado la subetiqueta, sus variables serin calculadas y afiadidas a p a g e c o n t e x t y, finalmente, su contenido de cuerpo seri evaluado. La salida seri parecida a la siguiente captura de pantalla:

Extensiones de etiqueta JSP

Hello Rod. You F e entry 0 in my list. Nafionality: Australian City: London Hello k a b e h . You 're entry 1 in my list. Australian City: a d m y Hello Bob. You 're entry 2 in my list. NaiionaLi~: Hello Jens. You 're entry 3 in my list. More HTML

& ist to

rr[@

Ll
local intranet

Intente carnbiar el ejernplo para trasladar la etiqueta<examples : n a m e I n f o > fuera del alcance de una etiqueta < e x a m p l e s :h e l l o s > . Su rniquina JSP debe proporcionar un rnensaje de error de ayuda, incluido 10s tkrrninos de la excepci6n que en este caso lanza NameTag. Corno siernpre, algunos servidores rnostrarin este rnensaje de error a1 cliente; otros, corno WebLogic 6.1, rnostrari una pagina genirica de "Error Interno" per0 registrarin el error. Una vez rnis hernos visto el poder de la capacidad para definir variables de directiva. Puesto que las irnplernentaciones de las etiquetas no contienen ninguna anotacion, podriarnos ficilrnente utilizar estas etiquetas para generar un tip0 de contenido diferente a HTML.

Validar el uso de extensiones de etiqueta en paginas


Corno hernos visto, 10s descriptores de biblioteca de etiqueta nos otorgan algo de control sobre una extensi6n de etiqueta utilizada en piginas JSP. Por ejernplo, podernos especificar qu6 atributos estin perrnitidos e incluso cuiles de ellos son requeridos. Podernos declarar las variables de directiva que la etiqueta pone a disposici6n de las paginas JSP que lo utilizan. Sin embargo, hay ocasiones en las que quizis se requiera una validaci6n rnis sofisticada. Imagine una etiqueta u s e r D e t a i l s que exponga 10s detalles de usuarios registrados corno variables de directiva. Para identificar a1 usuario en cuesti6n, la etiqueta tiene tres atributos, u s e r n a m e , p a s s w o r d y u s e r i d . Puesto que un usuario puede ser identificado en el sisterna rnediante una cornbinaci6n exclusiva de nornbre de usuario/contraseha o rnediante una clave nurnirica prirnaria u s e r i d , la etiqueta podria ser utilizado de dos forrnas: especificando 10s atributos de nornbre de usuario y contrasefia, o especificando s610 el atributo u s e r i d . Proporcionar 10s tres atributos o cualquier cornbinacion diferente a estas dos no tiene sentido. En una situaci6n ideal, nos gustaria poder rnarcar el uso invilido en el periodo de traduccibn, en lugar de en el periodo de ejecuci6n. Por desgracia, no podernos hacerlo utilizando las definiciones de atributo del TLD. Todo lo que podernos hacer es rnarcar 10s tres atributos corno opcionales, lo que perrnitiria la cornposici6n de piginas JSP absurdas que proporcionara ninguno de 10s tres elernentos.

JSP 1.2 ofrece dos forrnas de ejecutar esta sofisticada validacion. Bien puede proporcionarse una clase T a g E x t r a I n f o que ejecute lavalidaci6n requerida opuedeasociarseun o b j e t o ~ a g ~ i b r a r y ~ a l i d a t o r

Capitulo 11
a la biblioteca de etiquetas en conjunto utilizando el sub-elemento < v a l i d a t o r > del elemento de nivel superior < t a g l i b > . El primer mitodo ha estado disponible desde la versi6n JSP 1.1; el segundo ha sido introducido en JSP 1.2.

La implementacidn de esta sofisticada validacidn va ma's alla' del alcance de un capitulo introductorio sobre extensiones de etiqueta pero b t e es un breve analisis sucesivo de cada uno de estos enfoques.
Hemos visto anteriormente el uso de una clase T a g E x t r a I n f o como un mod0 de declarar las variables de directiva expuestas por una etiqueta. Si una clase T a g E x t r a I n f o es utilizada, la miquina JSP invocarin su metodo Booleano i s V a l i d ( T a g D a t a d a t a ) en el periodo de traduccion. La clase j a v a x . s e r v l e t . j s p . t a g e x t .T a g D a t a habri sido poblada por la miquina JSP con datos sobre 10s valores atributos dados a la etiqueta por la JSP. Tanto 10s nombres como 10s valores de atributos estiticos estarin disponibles per0 s610 10s nombres de 10s atributos con valores de periodo de ejecuci6n estarin disponibles. Esta funcionalidad es ficil de utilizar y lo suficientemente capaz para resolver el problema que hemos identificado con la etiqueta u s e r ~ e t a i l analizado s anteriormente. Podriamos comprobar que 10s atributos presentes formaban una combinaci6n legal. Puesto que es ficil de utilizar, la validation utilizando una clase T a g E x t r a I n f o es la mejor opci6n en muchos casos. El segundo enfoque, introducido en JSP 1.2, conlleva especificar en el TLD un objeto que amplie la clase abstractajavax. s e r v l e t .j s p . t a g e x t . T a g L i b r a r y V a l i d a t o r quepuedevalidarelusode etiquetas en toda la biblioteca de e t i q u e t a s . ~ a g ~ i b r a r y ~ a l i d a t contiene or un metodo con la siguiente firma:
String v a l i d a t e (String p r e f i x , String u r i , PageData page)

Este mitodo devuelve n u l l si el uso de la etiqueta es vilido y un mensaje de error si el uso no es vilido. Si una c l a s e ~ a g ~ i b r a r y ~ a l i d aes to especificada r en elTLD para una biblioteca de etiquetas, la miquina JSP debe invocar su mitodo v a l i d a t e ( ) en el periodo de traducci6n cada vez que una etiqueta de la biblioteca sea encontrado en una JSP. El argumento de prefijo identificari la etiqueta concreto utilizado, mientras que el argumento P a g e D a t a expondri la vista de documento XML de la pigina JSP. Utilizar una clase TagLibraryValidator en mas complejo que ejecutar la validaci6n utilizando la clase TagExtraInfo. Sin embargo, es mucho rnis eficaz. N o s61o pueden tenerse en cuenta 10s atributos pasados a la etiqueta; puede considerarse la estructura completa de la pigina. Todos 10s elementos de la pigina (declaraciones, scriptlets y datos de plantilla) estarin disponibles via navegaci6n del documento XML. Tambien es posible devolver un error de ayuda para el desarrollador JSP explicando qui ha fallado. Si se requiere una validaci6n de uso de etiqueta extremadamente sofisticada, una clase T a g L i b r a r y V a l i d a t o r puede solucionar casi cualquier problema. Sin embargo, para requisitos de validaci6n rnis sencillos, utilizar una clase T a g E x t r a I n f o seri igual de efectivo y mucho rnis ficil de implementar.

Manejo de errores
Algunos errores pueden evitarse mediante el uso de estricta validaci6n del periodo de ejecuci6r1, pero seguimos preguntindonos qu6 deben hacer 10s manejadores de etiqueta si encuentran una condici6n de error en el periodo de ejecuci6n. La respuesta depende de si el error es lo suficientemente serio para invalidar el trabajo de la pigina JSP llamante y de si es posible que la etiqueta sea tan importante para la estructura de la pigina como para justificar que la pigina llamante sea redirigida a una pigina de error. Si se trata de un error menor, la mejor soluci6n es producir una adecuada anotaci6n de error, o nada, dependiendo del prop6sito de la etiqueta. Podria afiadirse un comentario HTML que explique el error con

Extensiones de etiqueta JSP


mis detalles. Si el error es importante, el rnejor procedimiento es hacer que el metodo manejador de etiqueta que detecta el problerna lance una excepci6n J s p T a g E x t e n s i o n . En la rnayoria de 10s casos, esto provocari que la pigina llamante sea redirigida a una pigina de error. JSP 1.2 afiadeunanuevainterfaz, ja v a x . s e r v l e t .js p . t a g e x t .T r y C a t c h F i n a l l y , queofreceun enfoque alternative a1 rnanejo de errores. Las retrollamadas de la interfaz T r y C a t c h F i n a l l y pueden ser utilizadas para interceptar excepciones lanzadas por cualquier metodo rnanejador de etiqueta invocado por el contenedor en el period0 de ejecucion. Esto significa que si un manejador de etiqueta lanza una excepcion, no rornperi necesariamente la pigina JSP ni provocari que se rnuestre una pigina de error. En su lugar, la implernentaci6n del rnanejador de etiqueta tiene una oportunidad de reaccionar a la excepci6n.
y. aContiene ll dos Cualquier rnanejador de etiqueta puede irnplernentar l a i n t e r f a z ~ r y ~ a t c h ~ i n rnetodos, cuyos propbsitos quedan patentes en sus nornbres:
public void docatch (Throwable t) throws Throwable

Este metodo seri invocado si el metodo del rnanejador de etiqueta d o s t a r t ( ) , doEndTag ( ) o (si es aplicable) d o I n i t B o d y ( ) o doAf t e r B o d y ( ) lanzacualquier excepcion, verificadao sinverificar. Puede adoptar las medidas pertinentes y suprirnir T h r o w a b l e , o volver a lanzarla para que sea rnanejada por la JSP utilizando la etiqueta. Aunque este rnetodo puede lirnpiar cualquier problerna que pueda surgir, el contenedor no invocari llamadas posteriores en el manejador de la etiqueta para este uso de la etiqueta. (Es decir, si d o S t a r t T a g ( ) lanza una exception, inchso si d o c a t c h ( ) aplica con exit0 un rodeo, el contenedor no invocari doEndTag ( ) .)
public void doFinally
()

Este metodo seri invocado en todos 10s casos, se haya encontrado o no un T h r o w a b l e durante el trabajo de la etiqueta y puede ser utilizado para realizar una lirnpieza despues de cada invocaci6n del manejador de etiqueta. Observe que el metodo d o c a t c h ( ) no seri invocado si resulta una excepcion de la invocaci6n por parte del contenedor de un metodo configurador de propiedades en el rnanejador de etiqueta. Nuestro siguiente ejernplo muestra corn0 puede ser utilizada la i n t e r f a z T r y C a t c h F i n a l 1 y. Crea un ~nfv o c a t i o n p a r sirnularun a recurso que debe ser objeto ficticio l l a r n a d o t h i s ~ u s t ~ e ~ tuelrl~ liberado para evitar filtraciones de recursos. En este caso, si este objeto no es n u l l despues de una (posiblernente incornpleta) invocation de 10s rnktodos del rnanejador de etiqueta, imagine que tenernos una filtration de recursos que puede afectar la estabilidad de nuestro servidor. (En una aplicacion real, el recurso podria ser un socket o una conexion de base de datos.) Nuestro ejernplo utiliza las instrucciones s y s t e m . o u t para ilustrar el funcionarniento del contenedor y por ello necesitarernos referirnos a1 registro de nuestro servidor para revisar la salida:
packaqe import import import lmport tagext; j ava. io. IOExceptiort; java.uti1.'; javax.servlet. jsp.'; javax.serv1et.jsp.tagext.'; extends Tagsupport implements IterationTag, TryCatchFinally

public class TryCatchFinallyIterationTag

private List names; private int index; private StringBuffer output

new Strir~gBuffer ( ) ;

Caoitulo 11
Utilizarernos este objeto para decidir si lanzar o no la excepci6n:
private Rar~dom r a n d
=

new

Random();

La variable thisMustBeNullAfterInvocaction es utilizada para sirnular un recurso caro. Si no es n u l l , imagine que esta etiqueta ha dejado una conexi6n DB o un socket abierto:
private Object

thisMustBeNullAfterIr~vocation;
[

public L i s t getNames0 r e t u r n names;

I
p u b l i c v o i d setNames ( L i s t names) t h i s . n a r n e s = names;
[

I
public int doStartTag ( ) throws JspTagException
[

Presente el c6digo hash de este objeto, para rnostar la estrategia de reserva del contenedor:
System. o u t . p r i n t ( " - - - - \ndoStartTag hashcode() + ": " ) ; on tag with hashcode=

" +

Cornpruebe el uso del recurso: ningtin recurso debe ser consurnido antes de que cornencernos nuestro trabajo:
checkResourcelJsage ( ) ;

Sirnule asignar el recurso caro:


thisMustBeNullAfterIr~vocatior~ = new setloopvariables ( ) ;
Object ( ) ;

El valor de retorno es el rnisrno que el de una etiqueta normal, no iterativo:


return EVAL B O D Y INCLUDE;

La miquina JSP invocard este rnktodo cada vez que haya sido procesado el contenido de cuerpo de esta etiqueta. Si devuelve S K I P-BODY,el contenido de cuerpo habri sido procesado por dtirna vez. Si devuelve EVAL-BODY-TAG, el cuerpo seri procesado corno rninirno una vez rnis, a1 igual que este rnktodo. Alrnacenarnos contenido en S t r i n g B u f f e r , en vez de escribir directamente inforrnacibn de salida:
public int d , ~ i A f t e r B o d y ( )t h r o w s JspTagException

Si todavia no hernos llegado a1 final de la lista, siga procesando:

Lanzarnos una excepci6n cada cierto tiernpo, para dernostrar el funcionarniento de T r y C a t c h F i n a l l y :


if ( r a n d . n e x t I n t i 3 ) % 5 == 0 ) t h r o w new JspTagException("Randorn e r r o r " ) ; setLoopVariablesi ) ; r e t u r n EVAL B O D Y AGAIN;

I Si llegarnos hasta qui, hernos terrninado de procesar la lista:


return SKI P-BODY;

Extensiones de etiaueta JSP

p u b l i c i n t doEndTag() { Systern.out .println("doEr~dTag: " ) ; r e t u r r ~ EVAL PAGE;

1
Ponga la variable a disposici6n de cada iteraci6n:
private void setLoopVariables ( )
{

pageContext.setAttribute("name",
I

narnes.qet(index).toString()) ;
I n t e g e r ( i n d e x )) ;

p a g e c o n t e x t . s e t A t t r i b u t e ( " i r ~ d e x " , new

public

void

release()

Puede eliminar 10s comentarios de esta linea para ver c 6 m o maneja una miquina JSP la reserva de etiquetas:
//
Systern.out . p r i n t l n ( " r e l e a s e ?
;

d o E n d T a g ( ) puede n o haber sido invocado si se ha invocado este metodo. Alternativamente, el error puede haber surgido en el m i s m o d o ~ n d ~ (a)g :
p u b l l c v o l d doCatch(Throwab1e t ) throws Throwable { System.out . p r l r ~ t l n ("docatch: " + t ) ; t " < f o r ~ tc o l o r = \ " r e d \ " > " + pageContext . g e t o u t ( ) . p r l r ~ t l r( " I n v o k e d < b - d o C a t c h < / b > b e c a u s e of t t ")</font>");

("

~ s t see r i invocado despues de d o ~ n d ~ (a) g (si d o ~ n d ~ () a es g invocado):


public void doFinally() { Systern.out . p r i n t l n ("doFir1a11y: c l e a r ~ i n g up") ; / / Lirnpiar t h i s M u s t B e N u l l A f t e r I r ~ v o ~ a t i o= r ~n u l l ;

Este metodo comprueba que nuestro recurso deseado ha sido liberado sin problema:
private i f void checkResourceUsage ( ) { ( t h i s M u s t B e N u l l A f t e r I r ~ v o c a t i o r! ~= n u l l ) { System. o u t . prirjtlri ( "'+****CCCCC+ RESOTJRCE LEAK: else [ Systern.out . p r i n t l r , ("PPesource usage OK") ;

resource

n o n - n u 1 1" ) ;

La entradaTLD es sencilla. N o necesita especificar que este manejador de etiqueta implementa la interfaz TryCatchFinally:
tag> < n a m e > t c f I t e r a t o r ./name> <:tag-class~ta~ezt . T r y C a t c h F i r ~ a l y lIterati~>r~Tag</tag-class> <body-content ~JSP</hody-cor1ter~t~ <description> Simple i l l u s t r a t i o n of TryCatchFinally i n t e r f a c e //description>

Capitulo 11
<variable> <name-given>name</name-given> <variable-class>java.lar~q.Strir~g</variable-class> </variable> <variable> <name-given>i ndex</ name-given> <variable-class>j ava. lang. Ir~teger</vari able-class> </variable> <attribute> cname>narnes~/name> crequired>t rue</ required> <rtexprvalue>true</rtexprvalue> </attribute> </tag>

La JSP ]lamante, t r y C a t c h F i n a l l y . j s p , es bastante similar a nuestro anterior ejemplo Iterator per0 su producci6nvariari porque el m i t o d o d o ~ tf e r ~ o ( d ~e ~ r ~ ~ a t c h ~ i n ) d t ear a l t l iy o~ n~a~lanza a veces excepciones e n el period0 de ejecucion:

< %!

java.uti1 .List names = new j ava.uti1.LinkedList public void jspInit [ ) { rtarnes.add [ "Rod" ) ; names. add("Isabel1e"); names. add ("Bob") ;

[ ) ;

W>

cb,.dy> <p:'HTML. Output generated using tags is italicized.c/p> <i> <p > <examp:es:tcfIterator names="<%=narnes%>"> Hello cb>c%=name%></b>. You're entry <%=index%> in my list.<br/> </exarnples:tcfIterator' c/p:> </ i> <p>More HTML. c/p> </body> </html>

La produccion variari c o n la elecci6n casi aleatoria de si el manejador de etiqueta debe lanzar una excepcion en su m i t o d o d o A f t e r B o d y 0 , per0 s e r i nlis o menos ask

Extensiones de etiqueta JSP

HTML Output generated u s q Q s 1 s ~tdclred


Hello Rod. You're ently 0 zn .mylist. Hello Isabelle. You 'ro ently I m my list. HeUo Bob. You're e n t v 2 in my hst.

Ii

0 si ocurre a l g h error, seri ask

HTML Output generated using tags is itahzed.

I1

Hello Rod You 'ro enfry 0 a n m y Bsf. d, ( ,l/d h ( '

dl
t,

.;

I
I

More HTML.

La miquina JSP registrar5 Ins retrollamadas que la etiqueta reciba. En el caso de la Implementation de Referencia, la siguiente salida apareceri en la ventana de la consola del servidor:

Capitulo 11
Debido a que hemos incluido el c6digo hash de la instancia de etiqueta en cada invocaci6n, esta salida tambikn revelari la estrategia de reserva que utiliza nuestro contenedor para manejadores de etiqueta. (Esta captura de pantalla ilustra que la Implementaci6n de Referencia n o esti reutilizando las etiquetas durante la mayor parte de tiempo.) Intente eliminar ~ r ~ ~ a t c h ~ i nde a la l cliusula l implements de este manejador de etiqueta. Ahora, el manejador de etiqueta n o tendri capacidad para suprimir excepciones y producir el HTML apropiado y la pigina llamante simplemente se romperi.

TryCatchFinally: i u n peligro para el diseiio?


Aunque hay situaciones en las que la interfaz TryCatchf Finally puede resultar htil, algunos desarrolladores tienen serias dudas sobre su uso en principio (e incluso la sabia idea de afiadirla a1 API):

O Utilizar un API para simular una funci6n de lenguaje perfectamente correcta (manejo de excepciones de Java) sugiere que algo va ma1 con lo que el API intenta hacer. O La opci6n TryCatchFinally puede instar a emprender tareas propensas a error como la recuperaci6n de datos en manejadores de etiqueta. Esto plantea dos problemas: las piginas JSP deben realmente ser utilizadas como vistas, implicadas en la presentaci6n mis que en la recuperaci6n de datos y puede que sea demasiado tarde para hacer algo adecuado con el error una vez que la etiqueta ha sido invocado. Por ejemplo: <quk ocurre si hemos perdido la conectividad a nuestra base de datos? Optando por acceder a ella unicamente en una etiqueta invocada despuks de que se haya completado una importante generaci6n de piginas, n o podemos estar seguros de que el bufer no ha sido vaciado y de que el contenido n o haya sido enviado de vuelta a1 cliente. Si ha sido asi, puede que hayamos generado informaci6n de formato irrelevante cuando realmente necesitibamos decir a1 cliente que n o podiamos ofrecer un servicio normal.
U n complemento bien recibido del API JSP en la versi6n JSP 1.2 destinado a1 manejo de errores de period0 de ejecuci6n es el nuevo constructor de JspException que toma un mensaje de stringy una causa de raiz Throwable. A1 igual que el constructor ServletException toma 10s mismos argumentos, esto facilita la adici6n de informaci6n de contexto util cuando se encuentra un problems, mientras que se preserva la traza de pila del problema. Por desgracia, (como en JSP 1.2 Proposed Final Draft 2) JspTagException todavia nq cuenta con un constructor con estos argumentos y ni siquiera un constructor que tome una causa raiz. Este es un descuido de la especificacih que dificulta aun rnis la escritura de aplicaciones mantenibles. La soluci6n, hasta que se disefie un API mis consistente, es crear una subclase de JspTagExcept ion para su organizaci6n, proporcionarle un constructor que tome un mensaje S t r i n g y una causa raiz Throwable y lanzarla en h g a r de JspTagException.

Eventos de ciclo de vida de aplicacion


La especificaci6n Servlet 2.3 (que esti intimamente relacionada con la especificaci6n JSP 1.2) introduce el concept0 de eventos de ciclo de vida de aplicaci6n y la capacidad de registrar cualquier numero de beans escuchadores que reciban notificaciones a medida que se van sucediendo. Hay dos tipos de eventos de aplicaci6n: eventos de contexto de servlet y eventos de sesi6n HTTP. Los eventos de contexto de servlet son activados cuando se ha creado un contexto de servlet y esti disponible para solicitudes de servicio, cuando un contexto de servlet esti a punto de cerrarse, o cuando 10s atributos del contexto de servlet han sido afiadidos, eliminados, o sustituidos. Los escuchadores de eventos de contexto de servlet puede ser utilizados para gestionar recursos o el estado mantenido para toda una aplicaci6n ( o biblioteca de etiquetas) en el nivel de miquina virtual. Deben implementar la interfaz

Extensiones de etiaueta JSP


j a v a x . s e r v l e t .~ e r v l e t ~ o n t e x t ~ i s t e n e r o l a i n t e r f a z javax.servlet.ServletContextAttributeListener. Los eventos de sesi6n H T T P son activados cuando un objeto H t t p S e s s i o n de usuario ha sido creado, invalidado, ha expirado o cuando 10s atributos han sido afiadidos, eliminados; o sustituidos en un objeto H t t p S e s s i o n existente. Los escuchadores de eventos de sesi6n HTTP pueden ser utilizados para gestionar recursos o el estado mantenido en nombre de un determinado usuario, o para mantener informaci6n sobre el uso de una aplicacidn completa. Deben implementar la interfaz j a v a x . s e r v l e t . http.~ttp~ession~ontext~istenerolainterfaz javax.servlet.http.HttpSessionAttributeListener. La especificaci6n JSP 1.2 se construye sobre esta nueva funcidn del API Servlet, permitiendo bibliotecas de etiquetas, asi como aplicaciones Web, para registrar escuchadores de eventos de aplicaci6n. Antes de analizar una sencillo ejemplo que muestra c6mo utilizar esta nueva funcionalidad de biblioteca de etiquetas, consideremos por qu6 ha sido introducida y qu6 necesidades cubre. Una caracteristica clave del mecanismo de extensi6n de etiqueta es la capacidad de distribuir bibliotecas de etiquetaes independientes que pueden ser reutilizadas en varias aplicaciones Web. Es importante que una biblioteca de etiqueta pueda ser utilizada sin modificar el descriptor de despliegueweb .xml de la aplicaci6n (ademis de elemento necesario < t a g l i b > para indicar a la aplicaci6n d6nde puede encontrar el despliegue de etiqueta). La capacidad de registrar escuchadores de aplicaci6n Web en bibliotecas de etiqueta significa que las bibliotecas de etiquetas pueden reaccionar seglin sea precis0 a eventos de aplicaci6n Web para coordinar el funcionamiento de todas las etiquetas que contienen, sin necesidad de modificar las aplicaciones Web que 10s utilizan. Consideremos un escenario realista. iQu6 sucederia si las clases de manejador de etiqueta de una biblioteca de etiqueta necesitan mantener recursos compartidos con un ciclo de vida vinculado a la biblioteca completa, en lugar de invocaciones de periodo de ejecuci6n que etiquetas individuales? Mliltiples etiquetas podrian necesitar acceder a un servidor EJB y requerir una referencia a un objeto de inicio de bean de sesi6n. Claramente, no seria eficiente para cada manejador de etiqueta conectar con este recurso cada vez que es invocado desde una pigina JSP. La gesti6n de la conexi6n de recurso pertenece a1 conjunto de la biblioteca, no a cada etiqueta individual. Podriamos enfrentarnos a este problema utilizando un objeto semifallo accesible desde todos las etiquetas per0 id6nde seria inicializado? Seria posible inicializarlo la primera vez que una etiqueta necesite el recurso en el periodo de ejecucibn, per0 esto seria una soluci6n poco elegante y con tendencia a provocar errores. Una mejor soluci6n seria utilizar un escuchador de contexto de servlet para conseguir el recurso y ponerlo a disposici6n de todas las etiquetas de la biblioteca cuando se inicie una aplicaci6n que utilice la biblioteca de etiquetas y liberar el recurso cuando la aplicaci6n se cierre. Aunque un escuchador podria ser registrado en el descriptor de d e s p l i e g u e ~ e b .xml de cada aplicaci6n Web utilizando para ello la bibl'loteca de etiquetas, esto complicaria el uso de la biblioteca de etiquetas; 10s desarrolladores que lo utilizan no necesitarian preocuparse por su instalaci6n interna. Sin embargo, si el escuchador es registrado en el mismo descriptor de la biblioteca de etiquetas, las tareas de la biblioteca de etiquetas seguirian siendo privadas y queda garantizado que trabajari del mismo modo en cada aplicacidn Web que la utilice. Veamos una implementaci6n de una versi6n simplificada de la citaci6n anterior. Imagine que necesitamos poner un objeto compartido a disposici6n de todas las etiquetas de nuestra biblioteca de etiquetas e x a m p l e s . Registraremos un escuchador de contexto de servlet en el descriptor de la biblioteca de etiquetas para inicializar el objeto compartido y ponerlo a disposici6n de las otras etiquetas y liberarlo cuando la aplicaci6n se cierre. Para registrar un escuchador de contexto de servlet, necesitamos afiadir un elemento < l i s t e n e r > a nuestro LTD. El elemento < l i s t e n e r > es inmediatamente anterior a1 primer elemento < t a g > (pero posterior a 10s elementos, < d e s c r i p t i o n > y < v a l i d a t o r > , si estin presentes). El elemento < l i s t e n e r > contiene un linico sub-elemento,<lis t e n e r - c l a s s > , que contiene el nombre cualificado

Capitulo 11
cornpleto del bean escuchador de contexto de servlet. Es posible registrar cualquier nurnero de escuchadores en un LTD utilizando rndtiples elernento <listener>, per0 s610 necesitarernos uno:
<listener> <listener-class> tagext. l i s t e n e r s . ExamplesTLDServletCor~textLister~er </listener-class> </listener>

Ahora necesitarnos implementar el bean escuchador tagext .Listeners. ~ x a m p l e s ~ ~ ~ ~ e r v l e t ~ o n t e x t ~ i s t e n e r q u e h e m o s r e g i s t r a d o c o m o escuchador. Observe que debemos proporcionar un constructor sin argurnentos, siguiendo las convenciones estindar de JavaBeans. S610 hay dos rnktodos en la interfaz
javax.servlet.ServletContextListener:
0 void contextInitialized(ServletContextevent s c e )

Este metodo seri invocado cuando la aplicacion Web sea iniciada. Podemos utilizarlo para inicializar nuestro objeto cornpartido.
0

voidconteytDestroyed(ServletContextEventsce)

Este mitodo sera invocado antes de que se cierre la aplicaci6n. Podemos utilizarlo para liberar cualquier estado rnantenido por nuestra biblioteca de etiquetas.
Hayunsolornktodo,get~erv~et~ontext ( ) ,enlaclase javax. servlet. ServletContextEvent, que nos capacita para acceder a1 contexto de senlet de la aplicaci6n actual. Utilizarnos el mktodo setAt t ribute ( ) de este objeto servletcontext para poner el objeto compartido a disposition de 10s r ibut e ( ) del manejadores de etiqueta de la aplicaci6n. (Pueden acceder a 61 utilizando el mktodo ge t ~ tt objeto Pagecontext disponible para ellos en el periodo de ejecuci6n, convirtiendo a1 objeto de contexto de servlet en un medio Gtil de reparto de recursos en el periodo de ejecuci6n.)

La irnplernentaci6n de escuchador es muy sencilla:


package import public tagext.lister~ers; javax.servlet.*; class

ExamplesTLDServletCor~textLister~er implements ServletContextListerler {


final String SHARED OBJECT N A M E
=

public public

static

"sharedObject";

ExamplesTLDServletCorttextLister~er ( )

1
sce)
{

public void c o n t e x t I r ~ i t i a l i z e d (ServletCoritextEvent DummySharedObj e c t d s o = rcew D u m m y S h a r e d O b j e c t (


) ;

System.currentTimeMil1is~)
System.out . p r i n t l n ( " P u t t i n g shared o b j e c t " + dso + " i n S e r v l e t C o n t e x t f o r examples t a g sce.getServletContextO.setAttribute(SHARED OBJECT NAME,

library"); dso);

1
public v o i d contextDestroyed(ServletCor~textEver~t sce) { System.out.println("ServletContext d e s t r o y e d e v k n t : w o u l d f r e e any r e s o u r c e s held"
) ;

"

I
1

Para ilustrar rnejor este ejemplo, el objeto cornpartido es muy sencillo, manteniendo simplemente la hora en que ha sido creado y exponikndola en un mktodo getCreationDate ( ) . U n objeto cornpartido en

Extensiones de etiaueta JSP


una biblioteca de etiquetas de producci6n probablemente obtendria y expondria recursos requeridos por etiquetas enla biblioteca:
package import public tagext. listeners; j a v a . u t i l . Date; class DummySharedObject timecreated;
{

private

long

p u b l i c DurnmySharedObj e c t ( l o r i g t i m e c r e a t e d ) this.tirneCreated = tirnecreated;


i

p u b l i c Date getCreation13ate ( ) { r e t u r n new D a t e ( t i m e c r e a t e d l ;

Puesto oue la c l a s e ~ x a m p l e s ~ ~ ~ ~ e r v l e t ~ o n t e x t ~ hasido isten reeistradacomo er unescuchador de context0 de servlet, todas las etiquetas de la biblioteca de ejemplos pueden asumir que el objeto compartido estarin disponible a travks del objeto Pagecontext disponible para ellos en el period0 de ejecuci6n. La siguiente etiqueta obtiene una referencia a1 objeto compartido e imprime su fecha de creaci6n a las piginas JSP que la utilizan:
package import import import import public tagext. listeners;

ja v a . i o . I O E x c e p t i o r ~ ; j ava. u t i l . Date; j avax . s e r v l e t . j s p . *;

javax.serv1et.jsp.tagext.TagSuppnrt;
class SharedObjectAccessTag exterlds Tagsupport
[

p u b 1 i c i r ~ td o E r ~ d T a g ( ) throws JspTagExceptiorl [ S t r i n g d a t e s t r i n g = new D a t e ( ) t o s t r i n g ( ) ; try I

Obtenga el objeto compartido:


DurnmySharedObj e c t d s o = (DumrnySharedObject) paqeContext.getAttribute(

Examp1esTLDServletCor~textLister~er.SHARECl OBJECT NAME,


i f

PageContext.APPLICAT1ON SCOPE); ( d s o == n u l l ) { t h r o w new J s p T a q E x c e p t i o n ( " E r r o r : s h a r e d o b j e c t not four~d i n s e r v l e t c o n t e x t . " I t s h o u l d h a v e b e e n made a v a i l a b l e b y t h e " "ExampleTLDServletCor~textListener");

" t

p a g e c o r ~ t e x. tg e t o u t ( ) . w r i t e ( " I g o t h o l d o f t h e s h a r e d o b j e c t , " t " a n d i t was c r e a t e d a t " t dso.getCreationDate0 ); catch (IOException e x ) [ t h r o w riew J s p T a g E x c e p t i o n ( " F a t a 1 e r r o r : " t " h e l l o t a g c o u l d n o t w r i t e t o JSP o u t " ) ;

Este valor de retorno significa que la miquina JSP debe continuar para evaluar el resto de esta pigina:

593

r e t u r n EVAL P A G E ;

Antes d e que podamos acceder a la etiqueta desde piginas JSP, necesitaremos a6adir el siguiente elemento <tag> a nuestroTLD, hello. tld. Utiliza exactamente la misma sintaxis que 10s elementos <tag> que hemos visto antes, puesto que el acceso del nuevo manejador de la etiqueta al objeto compartido es un detalle de la implementacidn de Java que n o afecta su uso desde piginas JSP:
<tag>

<name>listerierTest</r~ame> ~tag-class~tagext.listeners.SharedObje~tAcces~Tag</tag-class~ <body-content>JSF</body-content> <description> S i m p l e e x a m p l e n f J S P 1.2 TLD listener f u n c t i o n a l i t y . Tikes no attributes, a n d s i m p l y q e n e r a t e a HTML </description> ; / :aq'

La siguienteJSPsencilla,tld-listener.jsp,invocala n u e v a e t i q u e t a l i s t e n e r l e x t :

<+@

taylib u r i = " / h e l l u W prefix="examplesn

C>

<html:.
<head> < t i t l e > E x a m p l e of J S F 1.2 T L D l i s t e n q r </head> <body> < p > T h i s is s t a t i c o l u t p u t < / p > < i > < p > < e x a m p l e s : l i s t e r ~ e r T e s/ t ></p>c/i> < p i T h i s is s t a t i c u u t p l . l t a g a i r t . < / p > < / b u d y> </htrnl>
functiunality</title>

La siguiente captura d e pantalla ilustra la salida que deberiamos ver cuando solicitamos esta pigina JSP. Muestra que el objeto compartido ha sido inicializado por el objeto ExamplesTLDServletContextListener registradoenelTLD y al que ha accedido con Cxito el manejador d e etiqueta SharedOb j ectAccessTag en el period0 de ejecucidn. Si volvemos a solicitar esta pigina, la salida n o cambiara, ya que seguimos accediendo a la misma instancia de objeto compartido:

Arch~vo Ed1c16n Ver

Favorltos
-

Herrarmentas

--

Ayuda

This is static output

1got hold of the shared object, and ii was created d Mon Aug 20 15:47:04 BST2001

Extensiones de etiqueta JSP


Este registro de un escuchador de contexto de servlet en un TLD tiene probabilidades de convertirse en algo muy comhn en aplicaciones JSP 1.2 y ofrece un nuevo mod0 de integrar la implementacidn de las etiquetas en una biblioteca.

Puesto que un "objeto compartido" aeadido a1 s e r v l e t con t e x t tiene alcance de aplicaci6n, pueden acceder a 61 a1 mismo tiempo mtiltiples hilos y debe estar a salvo de hilos. Los temas son 10s mismos que para cualquier objeto con alcance de aplicaci6n en una aplicacio'n Web.
Los escuchadores de sesidn H T T P tambien puede ser registrados en TLD. El registro de un escuchador de sesi6n HTTP no cubre la misma urgente necesidad que el registro de escuchadores de contexto de servlet, per0 resultari util para algunas bibliotecas de etiquetas. Como ejemplo hipotetico, considere una biblioteca de etiquetas que va a ser lanzada como demostraci6n, que permite no mis de tres usuarios a la vez. La biblioteca de etiquetas podria registrar un escuchador de sesi6n H T T P que mantuviera una cuenta de sesiones activas. Lainterfaz j a v a x .s e r v l e t .h t t p .H t t p S e s s i o n L i s t e n e r contiene dos metodos:
v o i d sessionCreated(HttpSessionEvent e ) v o i d sessionDestroyed(HttpSessionEvent e )

La implementacidn del metodo s e s s i o n c r e a t e d ( ) podria incrementar un contador de sesion, mientras que el metodo s e s s i o n D e s t r o y e d ( ) podria disminuir el contador de sesi6n. Cada etiqueta de la biblioteca podria comprobar la cuenta de sesidn expuesta por el escuchador de sesi6n (que puede afiadirse a si mismo como un atributo del s e r v l e t c o n t e x t de la aplicaci6n) y lanzar una J s p T a g E x c e p t i o n si la cuenta de sesi6n sobrepasa el miximo.

Locuciones de extensiones de etiqueta


Para resaltar el funcionamiento de 10s manejadores de etiquetas, hemos utilizado deliberadamente ejemplo sencillos hasta este momento. Sin embargo, la gama de funcionalidad que puede aplicarse con extensiones de etiquetas es muy amplia. Algunas de las posibilidades rnis importantes son las siguientes:
0

Generar salida HTML ~ s t es e el uso rnis sencillo de las etiquetas personalizadas. Tiene algo de merit0 en el hecho de que un bloque estindar de construcci6n esti disponible y puede ser cambiado simultineamente siempre que aparezca, si es necesario. Sin embargo, en general, utilizar codigo Java para generar HTML es torpe e inflexible. Utilizar inclusiones estiticas JSP (mediante la directiva i n c l u d e ) puede ser una alternativa de mayor nivel. ~ s t es a una variante mis sofisticada de la anterior, que evita la generaci6n desordenada de anotacion en codigo Java y permite la modificacion de la anotacion generada sin recompilaci6n. Habitualmente, sera necesario disefiar y documentar un mecanismo para controlar la sustitucion de variables y cualquier otro mod0 de convertir la plantilla en dinimica. Una clase abstracta que a m p l i a ~ a g ~ u p p oo rB t o d y T a g S u p p o r t podriaproporcionar busquedaestindar de plantilla e interPolacion de variables para uso en todo el sistema. Esta es una locucion comun y puede resultar muy util en sistemas reales. Definir variables de directiva ~ s t es a normalmente una alternativa superior a utilizar etiquetas para generar anotaciones directamente, especialmente cuando afecta a la iteracion. Todo el flujo de computaci6n y control es

u Utilizar contenido de plantilla para generar salida HTML

Capitulo 11
controlado por las clases manejadoras de etiqueta, en lugar de la pigina JSP Ilamante, pero las variables de directiva son utilizadas en la pigina JSP para permitir que la generaci6n de anotaci6n sea alterada ficilmente. C o m o regla general, las etiquetas que definen variables n o deberian generar anotaci6n.
L I

Transformar o interpretar contenido de cuerpo de etiqueta Este es un uso muy eficaz de las extensiones de etiqueta, con un potencial pricticamente ilimitado. Por ejemplo, una etiqueta podria establecer una conexi6n de base de datos y ejecutar S Q L contenido en su cuerpo para mostrar 10s resultados. Una etiqueta podria implementar un intirprete para un lenguaje, proporcionando una sintaxis y funcionalidad completamente nueva dentro de las piginas JSP. (Por ejemplo, seria concebible disehar una etiqueta asp que interpretara un subgrupo de ASP para ejecutar c6digo de legado.) En algunos de estos casos, el valor tagdependent deberia ser utilizado para describir el contenido de cuerpo del TLD.

Algunas de las posibilidades de esta locuci6n no son compatibles con la escritura de cddigo mantenible. J S P es una norma, comprendida por una comunidad de desarrollo completa, mientras que su contenido de etiqueta puede no serlo, a menos que elija alguna otra norma, como SQL. Tambie'n es posible crear etiquetas anidadas que interacttien de forma sorprendente; esto tambie'n reduce la legibilidad.

o U n rol de portero
Una etiqueta personalizada puede comprobar el registro o alguna otra condici6n y redirigir la respuesta si el resultado n o es satisfactorio. Merece la pena considerar enfoques alternativos que utilizan Filtros de Sewlet 2.3 o un servlet controlador, en el patr6n de diseho de controlador frontal.
0 Ocultar el acceso a objetos de empresa o API que n o deberian ser visibles ~ s t es a una forma ficil de proporcionar una interfaz JSP a 10s datos de empresa. Sin embargo, observe que n o es coherente con un buen diseho de J2EE escribir etiquetas que pueden acceder a bases de datos via JDBC. Considere la alternativa de una verdadera arquitectura de n niveles, en la que 10s manejadores de etiqueta accedan a objetos de empresa tales como EJB de sesi6n que implementan el patron de Session Faqade de J2EE.
0

Exponer datos complejos Las etiquetas personalizadas pueden ser utilizadas para exponer datos (por ejemplo, en una lista o una tabla) que podrian requerir de n o ser asi 16gica JSP complicada para ser mostrados. Esta es una de las mejores aplicaciones de etiquetas personalizadas y normalmente el mejor mod0 de mostrar datos de este tip0 en piginas JSP. Manejar la iteraci6n Esta es una forma sencilla y prictica de evitar una profusi6n de scriptlets en piginas JSP. E n este caso, es especialmente importante hacer que las etiquetas Sean tan genkicos como sea posible.

Recuerde que las etiquetas personalizadas estin construyendo bloques y alcanzarin su mixima utilidad cuando puedan ser reutilizados ficilmente. Los siguientes principios ayudan a hacer que las extensiones de etiqueta Sean reutilizables:

o Conseguir que las etiquetas Sean tan configurables como sea posible. Esto puede conseguirse
mediante atributos de etiqueta y utilizando anidamiento para proporcionar contexto. Pueden utilizarse atributos opcionales alli donde 10s valores por defect0 puedan ser provistos.
O

Evitar la generacion de H T M L en manejadores de etiqueta a n o ser que sea absolutamente necesarlo. Cuando 10s manejadores de etiquetas deben generar H T M L debemos garantizar que el html puede ser utilizado en una amplia variedad de contextos. Intente evitar la generacion de <html>,

L I

Extensiones de etiqueta JSP


< f o r m > y otras etiquetas estructurales; en su lugar, considere la lectura de HTML desde un archivo plantilla.
0

Evitar que las etiquetas personalizadas realicen tareas inesperadas en 10s objetos r e q u e s t y response. S61o porque 10s manejadores de etiqueta pueden acceder a estos objetos a travks de P a g e c o n t e x t , no significa que sea una buena idea. Por ejemplo, i n o resultari obvio para un lector de una pigina JSP que utiliza una etiqueta personalizada que la etiqueta puede redirigir la respuesta? A menos que la documentaci6n de la etiqueta sea escrupulosa, imaginar esto puede requerir lanzarse al c6digo fuente de la etiqueta. Considere otro ejemplo: si una etiqueta vaciara el bfifer de salida de la pigina JSP, la miquina JSP no podria redirigir a una pigina de error si algo fallara durante la representacibn del resto de la pigina. Esto limitaria la utilidad de la etiqueta y, de nuevo, el funcionamiento seria un reto para un desarrollador de JSP.

Cuando y c6mo utilizar las extensiones de etiqueta es analizado con profundidad en el siguiente capitulo. El punto clave a recordar, sin embargo, es que debemos tener algo de precauci6n a1 utilizar las etiquetas personalizadas. Utilizar demasiadas extensiones de etiqueta puede hacer que las piginas JSP sean ilegibles: el resultado final sera su propio lenguaje, que puede ser el enfoque rnis eficaz para resolver un determinado problems per0 no seria inteligible para un observador externo, especialmente si sus etiquetas cooperan de forma compleja.

Las extensiones de etiqueta o etiquetas personalizadas son una extensi6n potente del modelo JSP. Su uso s61o esta limitado por la ingenuidad de 10s desarrolladores y un bloque esencial de construcci6n de interfaces JSP de correcta ingenieria. Las mejores en JSP 1.2 10s convierten en mucho rnis capaces y ficiles de desarrollar. Las extensiones pueden acceder a P a g e c o n t e x t de JSP y su funcionamiento puede responder dinimicamente a 10s atributos XML con que son invocadas, asi como su contenido de cuerpo. Son implementadas utilizando: Clases Java que implementan funcionamiento de etiqueta
O Archivos de Descriptor de Biblioteca de Etiqueta XML (TLD) que describen uno o rnis etiquetas

10s atributos que requieren


O

Clases extra opcionales que definen el funcionamiento de validaci6n y las variables de directiva introducidas por las etiquetas

Las extensiones de etiqueta son un mod0 valioso de separar presentaci6n de contenido en interfaces JSP. Puesto que son una parte estindar de JSP, existe un nGmero creciente de bibliotecas de etiquetas de terceros, que se estin convirtiendo progresivamente en bloques de construcci6n del desarrollo de JSP. Fundamentalmente, una vez asimilados 10s conceptos iniciales, las extensiones de etiqueta son notablemente faciles de desarrollar. El mecanismo de extensi6n de etiqueta nos permite construir extensiones portitiles, sencillas y expresivas para nuestras piginas JSP, todas ellas creadas sobre conceptos y maquinaria existente. En el siguiente capitulo, examinaremos algunos ejemplos rnis complejos de extensiones de etiqueta.

Escribir aplicaciones JSP con bibliotecas de etiquetas


La especificaci6n JSP versi6n 1.0 nos presenta la noci6n de acciones estindar o etiquetas JSP integrados que deben ser implementados por cada vendedor de servidor. Como autores de aplicaciones JSP, ahora podemos confiar plenamente en las acciones estindar y utilizarlas con independencia de la versi6n del contenedor JSP o servidor de aplicaci6n que utilicemos. La revisi6n de la sintaxis de JSP y la provisi6n de acciones estindar parecia un lujo para aquellos que utilizaban contenedores que se adherian vagamente a la versi6n 0 . 9 ~ de la especificaci6n. Ahora todo eso parece quedar muy lejos pero, en realidad, s61o acaba de desaparecer con la explosi6n y la popularidad de las tecnologias relacionadas con Internet durante 10s ultimos ahos. La especificaci6n establecia que futuras versiones proporcionarian un mecanismo de extensiones de etiqueta para permitir la definici6n de acciones personalizadas y que pudieran ser utilizadas indistintamente por desarrolladores de aplicaciones y vendedores de servidores de aplicaciones. La versi6n 1.1 de la especificaci6n JSP nos proporcion6 el mecanismo para definir acciones personalizadas empaquetadas como bibliotecas de etiquetas. Esta iniciativa fue recibida con gran entusiasmo por la comunidad Web y la comunidad Java y tuvo implicaciones directas para una serie de diferentes grupos:

o Autores de aplicaciones JSP podrian definir y utilizar sus propios etiquetas con alcance en la
aplicaci6n, proyecto u organizaci6n.
0

Vendedores de servidores de aplicaciones podrian proporcionar extensiones a su implementaci6n de la especificaci6n. Organizaciones de terceros podrian proporcionar bibliotecas de etiquetas comercialmente viables, especificas de su linea de empresa.

Capitulo 12
Proveer un rnecanisrno para definir nuestros propios etiquetas es fantistico pero, hasta el rnornento, no se ha realizado ninguna provisi6n para etiquetas estindar que se vinculen con uno de 10s productos de desarrollo rnis capaces del rnercado actual: Java. El API Java nos ofrece facilidades para acceder a archivos, recursos de red, bases de datos y una extensa garna de tecnologias de empresa. Se ha invertido mucho tiernpo y esfuerzo en Sun Microsystems y organizaciones de fuente abierta para reunir algunos conceptos y patrones de disefios comunes con el objetivo de facilitar el acceso a API Java y crear una biblioteca de etiquetas estindar JSP, JSP Standard Tag Library (JSPTL). JSPTL esti siendo definida y desarrollada a travks del Proceso de Cornunidad Java (JCP) bajo la Solicitud de Especificaci6n Java (JSR) 052 y puede encontrarla en http://www.jcp.org/jsr/detail/52.jsp. En este capitulo, vamos a identificar y centrarnos en rnuchos rasgos cornunes de las aplicaciones Web de base JSP. Como autores de aplicaciones JSP, todos hernos utilizado conceptos Java estindar corno la iteraci6n e instrucciones condicionales y estarnos experimentando con conceptos mis nuevos como la internacionalizacion, XML y XSLT. Ahora analizarernos c6mo la implementaci6n de estos rasgos puede ser unificada y facilitada utilizando bibliotecas de etiquetas. En particular, inicialmente:
0

Revisaremos las ventajas de las etiquetas personalizadas y las bibliotecas personalizadas

0 Examinaremos brevemente algunos ejernplos de las bibliotecas de etiquetas de vendedor y de fuente abierta disponibles hoy en dia.
0

Introduciremos la Biblioteca de Etiquetas Estindar JSP (JSPTL) y mostrarernos c6mo obtenerla y lo que abarca en la actualidad

Despuks seguiremos para demostrar el uso de 10s etiquetas que componen la JSPTL. Otros conceptos comunes, que no estin cubiertos por la JSPTL (pero que serin pronto definidos como parte de JSPTL), como la internacionalizaci6n, el manejo de formas HTML dentro de piginas JSP, Transformaciones XML y XSL (XSLT) tambikn serin tratados con detalle, utilizando algunas etiquetas reunidas e~~ecificamente para el objetivo de este capitulo. Despuks de haber tratado la JSPTL y otros rasgos de uso cornfin de las aplicaciones JSP, pasarernos a una aplicaci6n prictica y realista como ejemplo principal. Finalmente, concluiremos examinando la pr6xima evoluci6n de JSPTL.

Ventajas de utilizar bibliotecas de etiquetas personalizadas


La Plataforrna Java 2, Enterprise Edition (JZEE), define una serie de funciones clave corno proveedor de productos JZEE, proveedor de cornponentes de aplicacion, ensamblador de aplicaciones, desplegador, administrador del sisterna y proveedor de herramientas JZEE. En concreto, el proveedor de cornponentes de aplicacidn es responsable de producir 10s diversos cornponentes que forman una aplicaci6n J2EE. En realidad, este rol abarca una serie de funciones, como disefiador de documentos HTML, programador de documentos (aquellos que producen 10s componentes Web de aplicaci6n dinimica corno piginas JSP y serv!ets) y desarrolladores Enterprise JavaBeans (EJB). Muchas organizaciones cornerciales tienen equipos de desarrollo de aplicaciones y cornposici6n Web totalmente separados. Los desarrolladores no estin (y en rnuchas ocasiones, no quieren estar) preocupados con 10s entresijos de HTML y JavaScript para crear geniales piginas Web. A este respecto, 10s autores de piginas Web no quieren preocuparse por 10s aspectos especificos del modelado prictico 00 y el desarrollo de aplicaciones. S610 quieren tomar el contenido proporcionado y trasformarlo en una interfaz Web, a travks de la cual 10s usuarios interactGen con la aplicaci6n.

Escribir aplicaciones JSP con bibliotecas de etiquetas


C o n la separation de 10s roles de autor de paginas y desarrollador de aplicaci6n, las piginas JSP son un paso en la direcci6n correcta para colaborar en la separaci6n de la presentation (10s datos de plantilla estitica HTML) y el contenido (a rnenudo datos priducidos dinimicamente en forrna de ~ a v a ~ e a n s Esto ). es un contraste para, por ejernplo, 10s servlets en 10s que contenido y presentaci6n estin vinculados. Las etiquetas personalizadas colaboran algo mis en el proceso de separaci6n de presentacibn y contenido dentro de las piginas JSP. Introducir etiquetas personalizados en nuestras aplicaciones JSP tiene las siguientes ventajas:
3 Separaci6n de presentaci6n y contenido:
O

Los desarrolladores crean etiquetas personalizados Los autores de piginas disehan piginas Web

Encapsular funcionamiento y promover la reutilizaci6n. Las etiquetas personalizados escritos por desarrolladores de aplicaciones pueden envolver la creaci6n y el acceso a datos producidos dinimicamente desde varios recursos: bases de datos, EJB, Espacios Java, Objetos de Datos Java (JDO) y sistemas de archivos, y exponer datos a 10s autores de piginas Web. Ademb, la incorporation de etiquetas personalizados normaliza la distribution y construcci6n de piginas Web. Capacitar herramientas sofisticadas de composici6n y IDE. Muchos proveedores J2EE ofrecen sofisticadas herramientas de composition JSP, que simplifican el uso de etiquetas personalizadas en las piginas JSP o incluso ofrecen soluciones de personalizaci6n completa que generan contenido especifico para cada usuario o tip0 de usuario. U n ejemplo es el Servidor de Personalizaci6n WebLogic de BEA.

Algunos ejemplos de bibliotecas de etiquetas personalizadas son analizados en la siguiente secci6n.

Ejemplos de bibliotecas de etiquetas existentes


El ritmo acelerado de desarrollo de webs comerciales ha provocado la aparici6n de diferentes bibliotecas de etiquetas de vendedor y de fuente abierta. Esto es fantistico para 10s autores de aplicaciones JSP, que tienen una variedad de etiquetas para elegir. El uso de una o varias bibliotecas de etiquetas realmente amplias y bien documentadas provocari curvas cortas de aprendizaje para desarrolladores JSP. Imagine poder pasar de un proyecto a otro y reutilizar las mismas bibliotecas de etiquetas. Hay muchos ejemplos de bibliotecas de etiquetas en la actualidad:
0

WebLogic Server 5.1 y 6.0 de BEA; Servidor de Comercio y Personalizacidn estindar con plantillas de base JSP personalizables. Vkase http://commerce.beasys.compara mis detalles. aplicaciones de ernpresa, que simplifica en gran rnedida el desarrollo de aplicaciones JSP. Vkase http://www.allaire.con7/products/jrun.

0 JRun 3.x Enterprise Server de Allaire; JRun ofrece algunas etiquetas 6tiles y sencillas para

El Proyecto Taglibs Jakarta; un repositorio en marcha de fuente abierta para bibliotecas de etiquetas personalizados JSP y herramientas asociadas. Este proyecto de Jakarta, parte del esfuerzo de la fundaci6n Apache Software Foundation, esti colaborando en la definici6n de JSPTL y muchos de 10s contribuidores participan activamente en la formaci6n misma de JSPTL. sobre este proyecto en http://jakarta.apache.org/taglibs/index.html.

O JSPTL es lanzada a travks del Jakarta Taglibs Project y animamos a1 lector a conocer algo mis

Capitulo 12
Con la llegada de JSPTL, espero con entusiasmo el dia en que todos podarnos trabajar con una biblioteca de etiquetas unificada, que abarque gran parte de la funcionalidad comun ofrecida en la actualidad por la variedad de bibliotecas de etiquetas disponibles.

Introduction de la Biblioteca de Etiquetas


Esthdar JSP (JSPTL)
JSPTL es una Biblioteca de Etiquetas de Piginas JavaServer estindar. Encapsula funcionalidad central, cornun a rnuchas aplicaciones JSP. Por ejernplo, en lugar de utilizar scriptlets o etiquetas especificos de vendedor para conceptos bisicos corno la iteracidn en listas, JSPTL define un estindar para cada etiqueta que lo consigue. Poco despues del lanzarniento de la especificaci6n JSP 1.1, se observ6 que el uso extendido de etiquetas personalizadas podria desembocar en la duplicaci6n del esfuerzo para definir etiquetas que accedieran a nuestros conocidos API Tava. Con una creciente aceotaci6n de la esoecificaci6n., Dronto de hizo Datente que esto podia suceder dernasiado pronto y apareci6 JSR-052 para atajar este problerna. JSR y el debate posterior por parte de la industria hizo surgir JSPTL.
L

Las ventajas obvias de la introducci6n de una biblioteca estindar de etiquetas son las siguientes:
O Una interfaz consistente para etiquetas cornunes entre vendedores de servidores de aplicaci6n.

Corno 1as acciones estindar, 10s desarrolladores pueden confiar en estas etiquetas para que esten presentes y sean implernentados de forrna consistente. Todo lo que 10s desarrolladores necesitan hacer es ernpaquetar JSTL con la aplicaci6n.
0 Reune ideas comunes para etiquetas litiles que proporcionan acceso a 10s API Standard Edition y

Enterprise Edition.
0 Sirnplifica el desarrollo de JSP y aplicaciones Web. 0 0

Reduce la cantidad de c6digo de scriptlet en plginas JSP, de una rnanera unificada. Perrnite una mayor integraci6n de herrarnientas de cornposici6n JSP en el desarrollo de aplicaciones Web.

En el momento de la publicacidn de este libro, JSPTL ha sido lanzado en Early Access EA1.l. Todavia esta' en su fuse inicial pero u n conocimiento mris profundo probablemente influird a partir de ahora el modo de escribir paginas JSP. Las siguientes secciones describen cdmo conseguirlo y en que' consiste JSPTL.

Obtener JSPTL
JSPTL es liberado a traves del proyecto Jakarta Taglibs. Puede ser descargado desde http:// jakarta.apache.org/taglib/doc/jsptI-doc/intro.html. Descargue la entrega JSPTL y descargue la docurnentaci6n del vinculo anterior. Necesitarin ejecutar 10s ejernplos que siguen en este capitulo.

lQue abarca JSPTL?


JSPTL EAl.l abarca 1as siguientes ireas:

Escribir aplicaciones JSP con bibliotecas de etiquetas


0 Flujo de control
0 0 0

Iteration
L6gica condicional

Lenguajes de expresi6n

0 Etiquetas de lenguajes de expresi6n

El punto clave durante las fases iniciales de JSPTL es disefiar y construir las bases de la variedad de etiquetas que serin incluidos en Gltirna instancia. Hacerlo correctamente y conseguir una biblioteca popular y utilizable dependerd en gran medida del trabajo llevado a cab0 durante 10s prdximos rneses. Por el rnornento, abarca las forrnas iterativas y condicionales de flujo de control. Posteriorrnente, se preve que abarque la internacionalizaci6n, JDBC, plantillas JSP, XMLIXSLT y I/O. Es rnds, JSPTL prornete etiquetas que se vinculen a JZEE, corno JavaMail, JNDI, JMS y rnuchos de 10s ~rornetedores API JAX corno JAXM, JAXB y JAX-RPC.

lniciarse en JSPTL
JSPTL EA1.l utiliza caracteristicas de la especificaci6n JSP 1.2 y por ello requiere un contenedor acorde con JSP 1.2 y Servlet 2.3. Para el prop6sito de este capitulo, utilizarernos el servidor de la Irnplernentaci6n de Referencia J2EE de Sun per0 cualquier otro contenedor adecuado corno WebLogic Server 6.x de BEA serviri. Recuerde que, generalrnente, escribirnos aplicaciones Web para la especificaci6n, no para el servidor. JSPTL cornprende en realidad dos bibliotecas de etiquetas. Aunque las dos bibliotecas contienen virtualrnente las rnisrnas etiquetas, difieren en el rnodo en que 10s valores de atributos son especificados en el periodo de ejecuci6n a las etiquetas de cada biblioteca. La primera biblioteca de etiquetas, valores de expresi6n de periodo de ejecuci6n JSPTL ( j r ) , contiene etiquetas que aceptan valores de atributos corno literales de string o valores de expresi6n de periodo de solicitud ( r t e x p r v a l u e s ) que utilizan expresiones de scriptlet corno "<= script let-expr %> ". En capitulos anteriores, se ha presentado rnultitud de ejernplos r t e x p r e v a l u e s . El siguiente fragment0 JSP rnuestra un ejernplo del uso de la etiquetaf o r ~ a c h e la n biblioteca j r:

< j sp: useBean

id="companyPageBean" type=". . . " /:

<

Processing :

La prirnera linea es la directriz t a g l i b que lleva la biblioteca de etiquetas j r a la pdgina JSP. Todos las etiquetas de la biblioteca estardn precedidos del prefijo j r dentro del alcance de la pbgina. La tercera linea afiade un bean de pbgina de la cornpafiia, despues del cual, a partir de la quinta linea, itera una lista de ernpleados de la cornpafiia.

La segunda biblitoteca de etiquetas ( j x), JSPTL con apoyo de lenguaje de expresi611, contiene etiquetas que
d o aceptan valores de atributo corno literales de cadeba que pueden representar valores de expresiones de lenguaje de expresi6n ( e l e x p r v a l u e s ) y no aceptan r t e x p r v a l u e s . Los valores de atributos proporcionados a las etiquetas de esta biblioteca representan expresiones que son interpretadas y evaluadas por el lenguaje de expresidn configurado:

Capitulo 12

<!-

Frucessinq

->

En el ejemplo anterior, el uso del meta-caricter ($) en $ companyPageBean. e m p l o y e e s es definido por el lenguaje de expresion para discriminar expresiones de literales de string. Al comparar las dos bibliotecas de etiquetas, utilizando 10s ejemplos anteriores, podemos ver las diferencias a1 instante. La biblioteca j r es muy similar en su uso alas bibliotecas de etiquetas que hemos visto hasta el momento. Los valores de atributos son provistos explicitamente a travks de expresiones r t e x p r e v a l u e JSP. Por otro lado, la biblioteca j x introduce un concept0 muy importante: expresiones de lenguaje de expresion. Estas expresiones afiaden significado a 10s valores de literales de string especificados corno atributos a las etiquetas.

En el primer ejemplo, hemos tenido que situar un bean y despuis invocar 10s mitodos de obtenci6n (get)para las propiedades del bean en el que estamos interesados, es decir employees.En el segundo ejemplo, sin embargo, simplemente hemos nombrado el bean y la propiedad anidada en el bean en el que estamos interesados. Como hemos especificado esto utilizando la expresi611, Scompanypage~ean .employees,el evaluador de lenguaje de expresi6n lo evalua por nosotros situando el bean en alcance a inspeccionando la propiedad
employees.

En la siguiente seccion, analizaremos con detenimiento las etiquetas que componen JSPTL, con algunos ejemplos.

lntegrar JSPTL en sus paginas JSP


Hemos analizado las ventajas de las bibliotecas de etiquetas, examinado algunas de las bibliotecas disponibles y hemos presentado JSPTL. Antes de ver las etiquetas que componen JSPTL, construyamos nuestro primer ejemplo.

Un ejemplo de iteracion
Como un simple ejemplo para demostrar la capacidad de JSPTL, examinaremos la pigina JSP que itera una lista de colores. Hemos nombrado este sencillo ejemplo f o r E a c h C o l o r . j s p consecuentemente. Examinernos primer0 JSP y analicemos despuks el ejemplo creado:

.'html> 'tiead> < t i t l e > A n e x a m p l e JSPTL f o r E a c h </head\ <body bgc~,l3?r="#FFFFFFn> How d o e s one remember colors of

Tag

with

Colors!</title>

the

rainbow?<BR

Escribir aplicaciones JSP con bibliotecas de etiquetas

La primera linea importa la biblitoteca d e etiquetas JSPTL con apoyo de lenguaje de expresi6n ( jx). A continuaci6n, se encuentra una pequefia cantidad de H T M L para crear una tabla que albergue nuestra lista de colores. El Prea de c6digo compartida muestra la parte interesante. U n f o r E a c h T a g itera una lista de colores, creando una fila para cada color, que el fondo de fila configurado en el valor RGB de color.
C o n f o r E a c h C o l o r . j s p e n el lugar adecuado (viase la secci6n Ejecrrci6n), apareced la siguiente pantalla en su navegador:

tos

.. .

'jspTq
- -

How does one remember colors of the rainbow?

Examinaremos detalladamente las etiquetas que componen JSPSTL m6s adelante. Mientras tanto, ejecutemos este ejemplo. JSP f o r E a c h C o l o r . j s p hace referencia a la lista de colores mediante la expresi6n " $ c o l o r s ". Para crear colores para mostrar, utilizamos una clase de implementaci6n s e r v l e t C o n t e x t L i s t e n e r para

Capitulo 12
crear una lista de colores de muestra en el arranque. La clase, JSPTLExamples Init, se muestra a continuacion:
package import import import public jsptl.examples.startup; j a v a . u t i l . +; javax. s e r v l e t .+; w r i t i n g j s p s . j s p t l .examples . b e a n s . + ; class JSPTLExamplesIr~it implements ServletContextLister~er [

p u b l i c v o i d contextInitialized(ServletCor~textEver~t scEv) createData(scEv);

I
public void corltextDestroyed ( ServletCor~textEverit scEv)
{ )

/ / C r e a a t r i b u t o s c o n a l c a n c e JSP p a r a s u u s o en 1 0 s p r i v a t e v o i d c r e a t e D a t a ( S e r v l e t C o r ~ t e x t E v e r ~st c E v ) { / / Crea a l g u n o s c o l o r e s C o l o r B e a r ~ c o l o r s [ I = new C o l o r B e a n [ I [ new C o l o r B e a n ( " R i c h a r d ( r e d )", " F F 0 0 0 0 " 1 , ( o r a n g e ) ", " C 8 0 0 0 0 " 1 , new C o l o r B e a n ( " O f ( y e l l o w ) ", "FFFFOO") , new C o l o r B e a n ( " Y o r k ( g r e e n ) " , "OOFFOO") , new C o l o r B e a n ( " G a v e ( b l u e )", "OOOOFF"), new C o l o r B e a n ( " B a t t l e ( i n d i g o ) ", " 6 1 0 0 F F " ) , new C o l o r B e a n ( " I n ( v i o l e t ) ", "8COOFF") new C o l o r B e a n ( " V a i n

ejernplos

JSPTL.

1;
scEv.getServletContext ( ) .setAttribute ("colors", colors);

El contenedor de servlet invoca la clase J S PTExamples Ini t cuando la aplicaci6n es arrancada e inicializada. En nuestro ejemplo, el contenedor invoca el metodo context Initialized ( ) ,que simplemente invoca el metodo creat eDat a ( ) para crear una lista de colores y extraerlos en el context0 de servlet. La clase ColorBean, utilizada paracrear el array colors [ ] , es la siguiente:
package jsptl.examples.beans;
[

p u b l i c c l a s s ColorBean p r i v a t e S t r i n g name; p r i v a t e S t r i n g rgb; public ColurBean() 1 1

p u b l i c C o l o r B e a n ( S t r i n g name, s e t N a m e ( n a m e ); s e t R G B V a l u e ( r g b );

String

rgb)

I
p u b l i c S t r i n g getNarne() I r e t u r n name;

1
public void this.name
=

s e t N a m e ( S t r i n g name) name;

I
public String getRGBValue ( )
[

Escribir aplicaciones JSP con bibliotecas de etiquetas


return rgb;

1
public void setRGBValue(String rgb) { this.rgb = rgb;

1
public String tostring ( ) { return getName() + "-" + getRGBValuei
);

I
Creemos un ARchivo Web (WAR) para la aplicaci6n Web que albergari 10s ejemplos que reunimos en este capitulo. Como hemos mencionado anteriormente, utilizaremos funciones de las especificaciones JSP 1.2 y Senlet 2.3 por lo que ejecutaremos 10s ejemplos utilizando el senidor de la Implementaci6n de Referencia de Sun que se adapta a estas e~~ecificaciones. Lo Gnico que queda por hacer es definir el descriptor de la aplicaci6n Web, Web. xml. El siguiente es el archivo Web. xml para nuestro ejemplo:

<I

DOCTY PE W e b - a p p PUBLIC "-//Sun Microsystems, Inc. //DTD W e b Application 2. 3//ENW "http://]ava.sun.c0m/j2ee/dtds/Web-app 2 3 . d t d N >

<Web-app> <descriptiorl> Writing JSP Applications with Tag Libraries example Web applicaticn </description> <display-r,arne>JSPtagWAR</display-name>
<!-

A corltext parameter that specifies the default expression language for the application.

->
<context-param> <param-r~ame>j avax. servlet . j sptl. E x p r e s s i o r ~ E v a l u a t o r C l a s s < / p a ~ - a m - r ~ a m e > <param-value>org.apache.taq11bs.]sptl.lar~g.spel.Evaluator</paramvalue> </context-param>

Ahora estamos preparados para desplegar el ejemplo. Cree un directorio para el WAR, llamado j spTagApps. Despuks de crear el directorio raiz WAR, Cree ahora la siguiente estructura inferior, que incluya nuestro forEachColor . j sp,el JAR de la biblitoteca de etiquetas JSPTL (vkase Obtener JSPTL), 10s

Capitulo 12

descriptores de la biblitoteca de etiquetas JSPTL, los J A R J A X P j axp . j a r y c r i m s o n . j a r incorporado a s Iel n piatq u e t e a d e c u a d o e n W E B - I N F / c l a s s e s : JSPTLy, porsupuesto, la clase ~ S ~ ~ ~ x a r n p l e en

La estructura anterior puede residir en cualquier lugar de su sistema de archivos pero mantingala para 10s otros ejemplos de este capitulo. Finalmente, tambien puede desplegar c o m o un archivo W A R convirtiendo en J A R la estructura de directorio completa:

Ahora tenemos que afiadir el archivo W A R a un archivo EAR de la aplicaci6n, para lo cual utilizaremos la utilidad de la Herramienta de Despliegue RI. S61o necesitamos especificar (ademis del nombre del archivo EAR y el archivo W A R que deseamos) la raiz de contexto para nuestra aplicaci6n Web:

file Edit Tools Help

I ZI m l r d m IEIK
Q

fl Files
9

d~pplicaltons Q 0 JSPTagsAPP 0JSFtagW

6@

servers

Veamos ahora q u i etiquetas estin e n JSPTL EAl.1 y reunamos algunos ejemplos.

Etiquetas JSPTL

Empezaremos analizando algunos de 10s temas de disefio considerados por el equipo de JSPTL a la hora de reunir JSPTL. DespuCs examinaremos algunos de las etiquetas bisicas utilizadas e n conjunci6n con

608

.
11

Escribir aplicaciones JSP con bibliotecas de etiquetas


etiquetas rnis cornplejas de la biblioteca y despues definirernos etiquetas rnis cornplejos de iteracidn y condicionales.

Algunas consideraciones de diseiio de JSPTL


JSPTL ha sido reunido corno parte de un proceso de cornunidad Java, Java Community Process (JCP). Corno resultado, se ha llevado a cab0 un anilisis exhaustivo de las necesidades de la cornunidad Java y se ha ernprendido una fase de disefio. En particular, se han considerado 10s siguientes puntos: Mantener a1 minimo las interfaces de etiquetas. El nurnero de atributos de etiquetas se ha rnantenido en el rninirno para no "atestar" las interfaces de etiquetas y proporcionar etiquetas que puedan conseguir casi cualquier cosa mediante su arnplio numero de atributos.
0 C o m o una etiqueta colabora con su entorno. Las etiquetas con frecuencia colaboran con su

entorno irnplicita o explicitarnente. Las etiquetas colaboran irnplicitarnente con su entorno irnplernentando una interfaz perfectarnente definida que pueda ser expuesta por la jerarquia de etiqueta ancestro ( r n e d i a n t e e l r n C t o d o ~ a g ~ u p ~ .o fr it n d A n c e s t o r W i t h C l a s s ( . . . ) ). Las etiquetas colaboran explicitamente exponiendo inforrnacion a1 entorno en el que operan. Tradicionalrnente, en un entorno de directiva JSP, esto se ha conseguido exponiendo una o rnis variables de directiva.

o El equipo de disefio ha optado por no exponer inforrnacion utilizando variables de directiva como
caso general. En su lugar, se consigue colaboraci6n explicita exponiendo inforrnacion a traves de atributos de alcance, configurados utilizando la c l a s e s e r v l e t c o n t e x t . Teniendo en cuenta estas consideraciones de disefio, la siguiente section p'resenta las etiquetas rnis bisicas que conforman JSPTL.

Algunas etiquetas basicas


La siguiente tabla muestra las etiquetas JSPTL que son utilizadas en conjuncion con las otras etiquetas en JSPTL. Estas etiquetas son responsables de devolver el valor de un valor de expresidn de lenguaje de expresion, ya sea directarnente en la pigina JSP, o a travks de un atributo con alcance. Corno un efecto derivado de la decision del equipo JSPTL para conseguir que las etiquetas JSPTL creen atributos con alcance a petition, a traves de SewletContext, estas etiquetas son responsables de poner a disposici6n 10s atributos de alcance a la pigina JSP o a1 entorno tradicional de directiva JSP.
Etiqueta expr Atributo Descripci6n Evalua una expresion de lenguaje de expresion y produce el resultado para la igina JSP. Similar en cornportamiento alas expresiones de scriptlet , <%= ... %>.

J~F

La tabla continua en la pdgina siguiente

609

Etiqueta

Atributo

Descripci6n

value default

U n a expresibn de lenguaje de expresion, como espera el lenguaje de expresion configurado. Unaexpresion por defecto paraevaluar devolverelvalor, si laexpresion n o realma la evaluacion. El cuerpo de la etiqueta expr tarnbikn puede ser utilizado aracontener un valor por defecto o de retroceso si la expresidn no ha reaEzado la evaluation. Configura el resultado de una expresion en un atributo con nornbre y alcance. Ejernplo:

set

var value scope declare

El nornbre a asignar a1 atributo con alcance. U n a expresionde lenguaje de expresion cuyo valor debe ser especificado: page, request, session, o application. El valor por defecto es page. El alcance del atributo cuyo valor debe ser configurador: p a g e , r e q u e s t , s e s s i o n , o a p p l i c a t i o n . Elvalorpor defectoespage. Declara unavariable de directiva conel nornbre especificado y cuyo valor corresponde con elvalor de un atributo conalcance con el rnisrno nornbre. Este Esta etiqueta proporciona un puente, desde la forrna explicita de colaboracion de las eti uetas JSPTL con su entorno (a travks de atributos con alcance)>asta el entorno de directiva JSP. Esta etiqueta esti disponible en las bibliotecas de etiquetas j r y j x. Ejernplo:

id

Corno su iere la Especificaci6n JSP 1.1/1.2, este atributo significa el una variable de directiva que seri creada por la etlqueta y nornbre estari disponible despuks del de la etlqueta en la pigina JSP.

type

El tip0 declarado de la variable de directiva.

N o entrarernos en rnis detalles sobre estas etiquetas ahora. Ya hernos visto algunos ejernplos de su uso e irernos viendo muchos rnis a l o largo de este capitulo. Avancernos y veamos ahora las etiquetas de iteracibn y condicionales de flujo de control.

Etiquetas de flujo de control


Las etiquetas de flujo de control proporcionan el rnecanisrno para la inclusi6n condicional, ejecucion e iteracibn en piginas JSP. Aunque estos mecanisrnos pueden ser irnplernentados utilizando las correspondientes instrucciones de lenguaje de prograrnacion Java e n scriptlets JSP, esto puede resultar

Escribir aplicaciones JSP con bibliotecas de etiquetas


engorroso y (dependiendo del tamafio y complejidad de las piginas JSP) puede desembocar en una gran cantidad de c6digo Java en las piginas JSP. Ademis, imagine tener que emparejar una serie de pares compuestos de corchetes de instrucci6n ({ )) en una extensa JSP. Los problemas del c6digo Java y el emparejamiento de corchetes se ajustan cuando las instrucciones condicionales e iterativas son anidadas. Tener estas construcciones implementadas como etiquetas personalizados simplifica el desarrollo del mod0 mis natural. Considere el siguiente fragmento JSP utilizando scriptlets:

< % if <!-

(expressionl) { % > o t h e r HTML m a r k u p p r o d u c e d when e x p r e s s i o n 1 == t r u e > < % for (Iterator iter= m y L i s t . i t e r a t o r 0 ; iter.hasNext();) { com.acme.MyItem myItem = (com.acme.My1tem) iter.next();
%>

<

! o t h e r HTML m a r k u p t o be l o o p e d o v e r f o r e a c h I t e m <% if (expression2) [ % > <!o t h e r HTML m a r k u p p r o d u c e d when e x p r e s s i o n 2 <%


%>

i n myList
==

->

true

->

Examinemos ahora el mismo fragmento JSP con 10s scriptlets sustituidos por sus correspondientes implementaciones de etiqueta:

...
<j r: if test="<%= expressionl % > " > <!other HTML markup produced when expression1 == true -> < j r: forEach var="myItem" items="<%= myList % > " > < ! - other HTML markup to be looped over for each item ~n rnyList -> <fnd:if test="<%= expression2 % > " > <!other HTML markup produced when expression2 == true -> < / fnd : if> < / j r: forEach> </jr:if>

Podernos ver una notable diferencia entre las dos rnuestras de cddigo anteriores. Utilizar etiquetas personalizados para construcciones iterativas y condicionales introduce las siguientes ventajas:

O Minirniza la cantidad de c6digo Java en piginas JSP, reduciendo asi su tarnaiio


0 Reduce el riesgo de corchetes ma1 ernparejados y otros errores de period0 de cornpilacidn introducidos con el uso de scriptlets de Java 0 Perrnite a autores sin experiencia o sin experiencia en JSP utilizar conceptos farniliares sin necesidad de implernentacibn en Java 0 Tiende mas hacia la representacidn de paginas JSP corno docurnentos XML, introducidos por la especificacidn JSP 1.1 0 Las construcciones condicionales e iterativas son abstraidas sobre el lenguaje de prograrnacidn Java 0 Facilita la lectura de paginas JSP, que a su vez facilita su depuracidn

Examinemos las etiquetas de iteracibn y condicionales que acornpaiian a JSPTL.

Etiquetas de iteration
El nlirnero de etiquetas de iteracibn de JSPTL, hasta el rnornento, es reducido. De hecho, la siguiente tabla rnuestra 10s dos etiquetas que facilitan la iteracidn en piginas JSP. Puede argurnentarse que es algo positivo. N o s61o el nlirnero de etiquetas es reducido sino que 10s etiquetas y sus interfaces son t a m b i h sencillos. Las etiquetas de iteracibn de la biblioteca se rnuestran a continuacidn: Etiqueta Atributo Descripci6n La principal etiqueta para iteracidn. Esta etiqueta curnple la iteracidn de dos rnodos: sobre una lista de objetos y sobre un rango de valores. Para la iteracibn sobre una lista de objetos, se ajusta a un gran nlirnero de tipos de datos indexados Java estindar, incluido arrays y todas las irnplernentacionesde j a v a . u t i l . C o l l e c t i o n , j a v a . u t i l . I t e r a t o r , java.util.Enumeration, java.util.Map, java.sql.ResultSety java.util.~ashtable.Tarnbi~nseajustaaunjava.lang. String de valores separados por comas ("rojo","verde","azul"). Hernos visto fo r E a c h tag en accibn en la introduccion a la seccidn JSPTL,Zntegrar J S P T L en sus piginas JSP:

Para la iteraci6n sobre un ran o, el cuerpo de la etiqueta forEach es iterado el nlirnero de veces iniicado. Por ejernplo, para iterar entre 10 y 100, inclusive:

<j x : f o r E a c h v a r = " n l ' b e g i n = " 1 O We n d = " 1 0 O W >


The v a l u e i s < j x : e x p r value="$n"/></TD> </jx:forEach>

Escribir aplicaciones JSP con bibliotecas de etiquetas

Etiqueta

Atributo

Descrivci6n Es importante destacar que 10s modos pueden sercombinados para iterar un rango de elementos en una coleccr6n.

var

El nombre a asignar al atributo con alcance que representa en elemento actual de la colecci6n que esti siendo iterada. En el caso en el que el objeto de Iteraci6n es j a v a .u t i l .Map, el elemento actualexpuesto s e r i u n nel j a v a . u t il . ~ a ~ . ~ n t r y o b j e c t . EcasoenqueelobjetodeIteraci6n es un j a v a .s q l .R e s u l t S e t el elemento expuesto actual seri el j a v a . s q l .R e s u l t S e t , situadoen lasiguiente fila. El tip0 de datos indexados o la colecci6n de elementos para ser iterados. U n objeto deestado que re resentaelestadoactualdel ciclo de iteracion. Este es un tipo definrdo ~ P P T L , j avax s e r v l e t j s p t l . ~terator~ag~tatus.Estainterfazes analizada en la siguiente secci6n.

items status

begin end step

U n valor de inicio de rango. U n valor de fin de rango. La iteraci6n sobre un ran o devalores s61o procesarivalores en el ran o en cada elemento "stept' $el rango o coleccidn que esti siendo itera&. La etiqueta f o r T o k e n s es una extensi6n de laetiqueta f o r E a c h . Proporciona el mismo funcionamiento, solo que itera sobre un string de valores delimitados.

<j x : f o r T o k e n s

v a r = " c o l o r " i t e m s = " r e d I g r e e n \b l u e " d e l i m s = " 1 "> The c o l o r i s <j x : e x p r v a l u e = " $ c o l o r " / > < / j x : forTokens>

var items status begin end step

Mismo comportamiento que el atributo var de f o r E a c h T a g . U n string o una expresi6n de lenguaje de expresiones que evallia a un j a v a l a n g . S t r i n g que contiene 10s valores delimitados a iterar.

Mismo comportamiento que el atributo s t a t u s de f o r E a c h T a g . Mismo comportamiento que el atributo b e g i n de f o r E a c h T a g . Misrno cornportarnicnto quc el atributo end de for&achTag, Mismo comportamiento que el atributo s t e p de f o r E a c h T a g .

Veamos ahora 10s ejemplos que acompaiian a JSPTL para aprender mis sobre las etiquetas de iteraci6n. A1 descargar JSPTL, tste incluye un ejemplo de aplicaci6n Web, j s p t l - e x a m p l e s . w a r , que muy litil para examinar todas las posibles combinaciones de uso de etiquetas de iteration y condicionales. El archivo WAR de ejemplos para JSPTL requiere la liltima versi6n de Tomcat para su ejecuci6n (disponible en http://jakarta.apache.org~tomcat/index.html).Para ejecutar 10s ejemplos, simplemente traslade j s p t l - e x a m p l e s . w a r a1 directoriowebapps de Tomcat y reinicie el servidor. La siguiente pactalla muestra la pigina de bienvenida de la aplicaci6n de ejemplos JSPTL:

Capitulo 12

JSPTL Early Access

Beware - API and Tags ~naylwill change

SYJIJILO.~~

!!e.wd~jw.e.~~ c.oIIIDB_~~PIo~JS

JSPTL Examples Introduction Iterators Conditionals EL_Support Mlsc

1 Welcome to the jsptl-examples web application!

I
1

Th~s web appl~cat~on mcludes avanetq of sample JSP pages that showcase the JSPTL tags currentv being specified mthm the I Ktr E r ~ ~ I--~IIII~I rt WARNING: This is EARLY ACCESS (EA). The goal of this EA program is to keep the community informed of the EG's progress as well as to give the community a chance to experiment with the standard tag library (JSPTL) early in the specification process so that valuable feedback can quickly be channelled back to the Expert Group.

I11
I/I
1

Documentation
Documentabon on the JSPTL tags IS mallable at litt@I!1ek3R8 m3che : ~ I $ [ & Q ~ I ~ ~ I It I is~ also ~ ; ava~lable IC as the jsptl-docs web appllcat~on of the jsptl EAl release

Mailing Lists
There are three ways to obtam ~nforrnat~on from or send your comments to Ihe JSR052 Expert Group
1 Support For supportkrsage queshons, please use the user rna~l~nq I~st ofjakartatagl~bs 2 Development For bugs, developmentrelated quesnons, please use the r)vk+lr~pr rmllni~ 1151 otjakarta-tagllbs 3 Comments to the JSROS2 EG To prwde the Ewert Group vnth feedback on the JSPTL, use ether the di.rl~:~pGrS ni ?Illno11y at Jakarta or you may contact the ewert group pr~vateiy at ~sn!': ~ g n l m w t s r ~ ~.oin u n All comments wrll be read, butwe cannot guarantee a personal rspty lo all messages recewed

/I

Examples
The JSPR examples have been d~nded mthe follwnng categoy

Ejecutando Tomcat, puede llegar hasta esta pigina via http://l0calh0~t:8080/j~ptl-examples. Haga clic e n el vinculo Iterator Tags (Etiquetas de iterador) y Ilegad a la pigina para explorar y probar las etiquetas de iteracion:

Escribir aplicaciones JSP con bibliotecas de etiquetas

JSPTL Early Access

Beware - API and Tags mayfwill change

sunnort developntent comments to JSR052 EG

JSPTL Examples Introduction lterators Conditionals EL Support

Mist

lterator Tags Examples


Simple

Pb P%

Simply displays the default tostring() value of the items in the customers collection

Range

Another simple example. Similar to the previous one, except that in this case there is no collection to iterate over. The items attribute is optional in the <forEach> tag. When it is not specified, the range attributes must be used to iterate a specific number of times over the tag's body. In this example, we simply iterate over the integer values specified by the range attributes.

Data Types

/@

The <forEach> tag supports a large number of data types for the collection of objects to iterate over. In this example, we feature the following data types: array of primitives, array of objects, Enumeration, Properties (Map). String (Cornma Separated Values).

Iteration Status

1b
Ti
Local intranet

The iterator tag exposes a wealth of information relative to the iteration taking place This example features some of that status information.

A travis de esta plgina, puede explorar cada etiqueta ejecutando cada ejernplo y buscando en el c6digo el ejeniplo a travCs de dos vinculos de iconos. Por ejernplo, si ejecutamos el ejernplo Iteration StatusTag (Etiqueta de estado de iteraci6n) obtenemos la salida que se muestra e n la siguiente captura de pantalla:

Capitulo 12

I d~ireccih(& ht~p://localhost:3080/jrptIIexarnpIc~/ite~ato~~/Stat jsp 3


. . .

- -

-. -. -

&1r

--

Iteration Status
Using statusinformation: current, index, count, fwst, last

There are 5 customers in the list.

Iteration using range attributes

sequence: 100 105 110 115 120 125 130 135 140 145 150 155160 165 170175180185180185200 There are 21 numbers in the list.

podemos ver c6mo ha sido escrito el ejemplo:

Escribir aplicaciones JSP con bibliotecas de etiquetas

Source code for: /iterators/Status.jsp

is@ cacjlib pref ix="jxW uri="htcp:// java.sun.com/ jspcl/ea/jx" 'r> chtmlz <head> <title>JSPTL: Iterscor Support -- Iteration Status Example</tiele> </head.> body bgcolor="#FFFFFF"> <h3>Iteration Scatus</h3> <h4>Using status information: current, index, count, first, last</h4> <table border="lP'> <tr> cth>index</th> ceh>counc/th> <th>last name</th> <th>f ir5t name</ th> <th>flrst?</th> ch>last?/ch> </cr> .:]x:forEach var="cuscomer" items="$customers" status="zcacus"> itr> ctd>jx:expr value="$status.index"/>c/cd> <cd><jx:expr value="$stacus.counc"/>/td> cd>jx:expr value="$scatus.currenc.lastName"/>/td> <td>cjx:expr value="$status.current.ficstNew/>/td> <td><jx:expr value="$status. f irstrf/>/td> <td>jx:expr value="$status.lastw/></td> </ tr> <jx: if test="$st~tus. last1'> jx:sec var="count" value="$~tacus .countn/> c/]x:if> </~x:forEach> /table> p>There are <jx:expr ~alue='~$count"/> customers in the list.

Para concluir el estudio de las etiquetas de iteraci6n JSPTL, analicemos 10s siguientes yuntos: Dentro del ciclo de iteration, la obtencion de informaci6n sobre el estado actual de ese ciclo

Capitulo 12
O Ampliaci6n de las etiquetas de iteraci6n para proporcionar forrnas personalizadas de iteraci6n
Estos dos ternas son analizados en las siguientes secciones.

Estado de iteracion
Las etiquetas f o r E a c h y f o r T o k e n s proporciona cada uno de ellos un objeto que puede ser utilizado para establecer el estado del proceso de iteracion. El nornbre del atributo con alcance creado puede ser especificado a travks del atributo status. El tip0 del objeto es j a v a x .s e r v l e t .j s p t l . I t e r a t o r T a g S t a t u s . lasiguientetablarnuestralas principalespropiedades delobjeto~terator~ag~ta creado: tus

Propiedad current index count

Tipo object Int int

Descripcih El elernento actual de la lista de elernentos iterados. El indice de base cero del elernento actual de lalista de elernentos iterados. Laposici6n de base uno del elernento actual del grupode elernentos elegible para su iteraci6n. Este valor aurnenta uno por cada elernento, mdependienternente de 10s atributos de inic~o, final opasode la etiqueta de iteracion. Por ejernplo, si inicio=l, final=lO y paso=2 entonces el grupo de elernentos susceptibles de iteracion es 1,3,5, 7 y 9. Tienen cuentas de posici6n de 1 , 2 , 3 , 4 y 5 respectivarnente. Indica si el elernento actual es el primer elemento del ciclo de iteraci6n. Indica si el elernento actual es el hltirno elernento del ciclo de iteration.

first last

boolean boolean

El ejemplo de estado de etiqueta de iteracibn, ejecutado e inspeccionado en la hltima secci611, muestra c6rno aplic6 correctarnente la inforrnaci6n de estado.

Capacidad de ampliacion de la etiqueta de iteracion


La mayoria de las tareas iterativas pueden realizarse con las etiquetas de iteration JSPTL. Sin ernbargo, si esto falla, el rnecanisrno de etiqueta de iteraci6n es ampliable. Si no puede conseguir lo que necesita con las etiquetas JSPTL, puede ampliar las etiquetas estindar y definir 10s suyos propios. La siguiente tabla muestra 10s tres tipos que JSPTL ofrece a 10s desarrolladores para asistir en la creaci6n de etiquetas de iteraci6n personalizados:

Tipo interface IteratorTag interface IteratorTagStatus

Descripci6n La interfaz principal para escribir etiquetas de iteraci6n personalizados. Las etiquetas de iteraci6n JSPTL roporcionan el estado del ciclo de iteraci6n dentro del alcance dePa eti ueta Las etiquetas de iteraci6npersonalizados queconforrnaniintkfazI t e r a t orTagdeben tarnbih proporcionar esta inforrnaci6n a travks del objeto ~ t e r a t o r ~ a ~ ~ t a t u s , chernosvistoen orno lasecci6nanterior,Estado de iteracz6n.

Escribir aplicaciones JSP con bibliotecas de etiquetas

I Tipo
abstract class IterntorTagSupport

Description
Clase abstracta para construir eti uetas de iteracidn personalizadas. Las etiquetas de iteracidn person$zados implementan 10s mitodos hasNext ( ) y next ( ) ,proporcionando el mecanlsmo de parada del ciclo de iteraci6n y 10s elementos iterados en la secuencia.

Etiquetas condicionales
De nuevo, como con las etiquetas de iteracidn, el numero de etiquetas condicionales hasta el momento en JSPTL es pequefio. Como se podria esperar, hay una etiqueta if y una etiqueta equivalente if -thenelseif-else oswitch,llamadochoose. La siguiente tabla muestra 10s cuatro etiquetas que facilitan el flujo de control condicional en piginas JSP: Etiqueta Atributo Descripci6n Una sencilla etiqueta condicional, que solo evalua su cuer o si la condicidn provista es t rue.La etiqueta tambiin, o cionafmente, expone un atributo con alcance que representa el vafor de la condicidn. Ejemplo:
<jx:if var="isMalen test="$employee.sex == 'M'"

>
The test for a employee is a male. </jx:if> < jx:if var="isMaleW test="$employee. sex /> The employee is male was <jx:expr value="$isMale"/> var test
==

' M ' "

El nombre a asignar a1atributo con alcance que representa el valor de esta condicidn evaluada como un Booleano. Una expresidn de lenguaje de expresibn, si es utilizada con la bibliotecade etiquetas ' x,o una expresidn de period0 de solicitud si es utilizada con la bibfitoteca de etiquetas j r.La expresidn debe evaluar un objeto primitiva boolean o un objeto boolean envoltorio. La eti ueta equivalente a la instruccidn switch de Java. El siguiente ejemp o muestra su uso:

choose

<jx:choose> <jx:when test="$employee.age >= 6 5 " > El ernpleado es pensionista. < / j x :when> <jx:when test="$employee.age >= 4 0 " > El empleado es de rnediana edad. </jx:when> <jx:otherwise> El emepleadono es demediana edadnipensionista. < / j x : othewise> </jx: choose>

Capitulo 12

Etiqueta

Atributo

Descripcih
-

S61oel cuerpo de laprimeraetiquetawhen cuya condici6ntruees evaluada. Si ninguna condici6n when es true, es evaluado el cuerpo de la etiqueta otherwise, si hay uno. when otherwise La etiqueta when, utilizado s61o en el contexto de una etiqueta de elecci6n progenitor. La e t i q u e t a o t h e r w i s e , utilizado s61o en contexto de una etiqueta de eleccion progenitor.

Para ver 10s ejern~los de etiquetas condicionales que acornpaiiaban a la descarga de JSPTL, haga clic en el vinculo Conditional Tags (Etiquetas condicionales en 10s ejemplo de la pigina principal, http:// localhost:8080/jsptl-examples/index.html. Llegari a la piginacondition Tags Examples (Ejemplos de etiqutas condicionales) que rnostramos en la siguiente captura de pantalla:

JSPTL Early

Beware

- API and Tags may/will


change

II

Access

sunnort develonment comments to SRO52 EG

JSPTL Examples Introduction Iterators Conditionals EL Support

&

II

Conditional Tags Examples


<itb Simple Conditional Execution

)%

Only shows a customer from the customer list if the last name is "Howe"

<choose> Mutually Exclusive Conditional Execution )

Customers from the USA will be printed in blue, those from Canada In red, and others In green

Custom Logic Tag

)%

JSPTL exposes in its API the abstract class ConditionalTagSupportto facilitate the implementation of custom cond~t~onal tags that leverage the standard conditional behavior defined in JSPTL.This example shows custom tag <usCustomer> that returns true if its customer attributevalue points to a US customer. It can be used both In the context of a simple cond~tional execution, as well as in the context of a mutually conditional execution by exposing the result of the conditional execution in a JSP page attribute via the tag attribute 'var'.

Si ejecutamos el ejemplo <choose> Mutually Exclusive Conditional Execution (Ejecucion codicional mutuamente excluyente), debernos ver la salida tal y como se muestra en la siguiente captura de pantalla:

620

Escribir aplicaciones JSP con bibliotecas de etiquetas

III

Mutually Exclusive Conditional Execution


USA:bloe Canada:red Others: green

[I] hcliard, M m x e ?5115/19?5 123 Cherrm F.oyal Ivlontreal Canada [2] M h t a , Stan 12/25/1947 45 Fisher Blvd Chicago U S A (320)876-9784 [3] Gilbert, Rod 0311 111951 123 Main Street New-York City USA
[4] Howe, Gordie 0712511946 7654 Wings Street Detroit USA (465)675-0761 (465)879-9802 [ 5 )S a ~ c h u kTcme . 1l/M/lP16 12 Maple Leafs Avenue Toronto Canada

LHO

l--r&

A
--

~ o c id nlrd

Si inspeccionamos entonces el c6digo para el ejemplo, debemos ver lo siguiente:

I
11

Source code for: IconditiondslChoose.jsp

=i I
II

<html> <head> <tltle>JSPTL: Condlclonel Supporc Mutually fxcluslve Conc c/ headz cbody bgcolor="#FFFFFF"> <h3>Mutually Excluslve Condlclonal Executlonc/h3>

--

<hl>WSA:blue Canada: red Ochers:grecn</h4> c~x:forEachvsr="customer" item*-"$cuscorrprs"> <jx:choose> cjx: when cest="Scuscomer address. country == ' USA' "> <font color="blue"> </jx:when> <jx:when test-"$customer.address.councry == 'Canada"'> <font color="red"> </ jx :when> <jx:otheruise> <font color="greenW> </jx:othcruise> </ jx:choose> cjx:expr value-nScustomern/>c/fonc>cbr> c/jx:forEach> </body> </hcml>

i l

Capitulo 12

Una aplicacion de registro y autentificacion


En esta seccidn, definiremos una aplicacidn generica de registro y autentificacidn que s e d construida y utilizada de forrna extensiva a lo largo del resto de este capitulo para probar las etiquetas JSP que iremos utilizando. Cualquier sitio Web que requiere que su usuario registre sus detalles, por motivos tales como compras on-line o suscripciones a servicios, tiene un sistema de registro y autentificacidn de este tipo. Los usuarios registran sus detalles en el sitio para poder utilizar 10s servicios del sitio. Los usuarios que posteriormente regresan a1 sitio deben autentificarse, normalmente introduciendo su nombre de usuario asignado y su contrasefia elegida. A lo largo de este capitulo, trabajaremos con un ejemplo de registro y autentificacidn porque es una aplicacidn muy comGn (y Gtil). Parece que, hoy en dia, uno nunca puede escapar de la obligacidn de introducir sus credenciales en Internet; tquiknes somos nosotros para cuestionarlo? Aunque la aplicacidn definida es muy simplista, nos proporciona una oportunidad ideal para demostrar cdmo gestionar la complejidad y minimizar parte de la confusion existente en nuestras piginas JSP, concretamente con iteracidn y k~gica condicional. Al mismo tiempo, dado que 10s sistemas de registro albergados en la Web estan expuestos a poblaciones de diferentes nacionalidades, analizaremos 10s objetivos de la internacionalizaci6n y la simplificacidn de piginas Web. El siguiente diagrama muestra 10s principales componentes Web de nuestra aplicacidn de registro:

Forrnularlo de entrada

I
tilTP/HTfPS

controlador del reglstro

I
-.
A

/reg~strat~on/log~n

Perf~lde usuarlo

/reg~strat~on/d~splayAIIReg~steredUsers /reg~strat~on/allRegsteredUsers xrnl

/reg~strat~on/d~splayReg~steredUserHobb~es

Escribir aplicaciones JSP con bibliotecas de etiquetas


Corno puede esperar de cualquier aplicaci6n de registro de una pigina Web, hay forrnularios para registro inicial y una entrada posterior. Tarnbikn aparece una pigina de presentaci6n para revisar sus detalles de registro y piginas para la adrninistraci6n de usuarios. Procederernos construyendo la aplicacidn de registro, paso a paso, desde la pigina de bienvenida hasta las piginas de adrninistracidn de la aplicacidn. A rnedida que vayarnos avanzando en el proceso, explorarernos las etiquetas que son utilizadas en cada pigina con el objetivo final, hacia el final del capitulo, de desplegar la aplicaci6n cornpleta. Empecernos entonces justo por el principio, con la pigina inicial.

La pagina de bienvenida
La pigina de bienvenida actua corno un punto de entrada principal para todas las funciones proporcionadas por la aplicacion. En realidad, la rnayoria de 10s sitios Web no tienen una pigina dedicada a1 registro. En carnbio, el registro y la autentificacidn tienden a estar ocultos detris de vinculos del sitio que asi lo requieren. La pigina de bienvenida aparece aqui para actuar corno el punto focal inicial para la aplicaci6n. La pigina es simple HTML con vinculos a1 resto de partes de la aplicaci6n. El cddigo para la pigina de bienvenida, i n d e x . html, es el siguiente:
<font face="arial, helvetica" size="4" color="#996600"> Welcome t o t h e Registration Home Page </ font><br> Cp>From here you can run all the components of the registration application. <br> Just click a n t h e links below: <o 1> <li>Register as a n e w user, <li>Login i n a s an existing <b>Note:</b>Yau mlust have <li>View y o u r user profile, Cb>Note:</b>Yau must have

<a href="register">Click Here!</a> user, < ' a href="login">Click Here!</a><br> registered first, within the same session. <a href="displayDetails">Click Here!</a><br> registered first, within t h e same session. < l i > < b > A d m i n i s t r a t i o r ~ < / b >- v i e w all registered users, <a href="displayAllRegistered~Jsers">Click Here!</a> < l i > < b > A d m i n i s t r a t i o r j < / b > - v i e w all registered users a s XML, <a href="allReqisteredUsers.xml">Click H e r e ! < / a > < l i > < b > A d m i n i s t r a t i o r ~ < / b > - v i e w all registered users and their hobbies, <a href="displayRegisteredUserHobbies">C1ick H e r e ! < / a > </ol>

Estudiaremos c6rno ejecutar la aplicacidn mis adelante. Por el rnornento, analizarernos el cddigo, explorarernos 10s principios ernpleados en cada pigina de la aplicaci6n y rnostrarernos las capturas de pantalla relevantes de la salida esperada. La pigina de bienvenida estari localizada en http://localhost:8000/ jspTagApps/registration/index.htrnl y aparece en la siguiente pantalla:

Capitulo 12

Welcome to the Registration Home Page

From here you can run all the components of the regstration application Just click on the links below:

1. Register as a new user, Click Htre! 2 L o pt n as an exis- user, Click Het-e1 Note:You must have registered first, w i h the same session. 3. View your user profile, Chck Here! Note:You rnust have registered first, w i t h the same session. 4. Administration - view all registered users, Click Here! 5. Administration - view all regstered users as XML, Click Here1 6 . Administration - mew all regstered users and their hobbies, Click Here!

C o m o hemos mencionado anteriormente y para futuras referencias, esta pigina puede ser utilizada para acceder a cualquier parte de la aplicacidn de registro.

El servlet controlador de registro


El Servlet Controlador de Registro proporciona el mecanismo para asociar solicitudes a piginas JSP Considere la siguiente arquitectura Model-View-Controller (MVC):

Escribir aplicaciones JSP con bibliotecas de etiquetas

Controlador

Navegadork 4

HTrP/HTrPS
Serdet

JavaBean

JavaBean

JavaBean

Cuando una pigina JSP es excluida, representa el contenido de su vista desde el JavaBeans mediante un servlet controlador en el period0 de ejecuci6n. Este sencillo enfoque a1 desarrollo de JSP y el mod0 en que separa control y logica de ernpresa de piginas JSP ha sido publicado como parte de J2EE Blueprints de Sun Microsysterns. H a dernostrado ser el rnejor enfoque aparecido hasta la fecha para producir aplicaciones de base Web fiables y reajustables. Independientemente de que el mecanismo proveedor sea sirnplemente un servlet controlador o un sisterna de rnanejo de solicitudes mbs elaborado, como el sisterna Struts de Jakarta, el modelo sigue siendo el rnismo. Puede encontrar mbs information sobre el proyecto Apache JakartaStrutsProjectenhttp: / / j akarta. apache. orgs/struts/index. html. Cuando una solicitud es planteada a la aplicaci6n, el servlet controlador realiza cualquier trabajo abiertamente, despuks decide qu6 pigina o piginas JSP debe invocar. En nuestra aplicaci6n de ejemplo, el proceso de decisi6n o "reglas" que deciden qu6 JSP es invocada para una determinada solicitud se encuentran en el mismo c6digo. En sistemas rnbs elaborados, como Struts, las reglas de asociaci6n pueden ser configurables a travks de propiedad Java por archivos XML. El c6digo para el servlet controlador, Regis t rat ioncont rollerse rvlet,es el que mostramos a continuaci6n:
package import writingj sps.registration; java.util.*;

Capitulo 12
import import import import import
j ava. io. IOException; j ava. sql . SQLException; javax.servlet.*; javax.servlet. http."; j ava. text. * ;

public class RegistrationControllerServlet extends HttpServlet { private static firla1 String USER COOKIE NAME = "writingJSPAppsUserCookie"; private static Strirlg regions[] = new String[] { "UK & Ireland", "Westerr, Europe", "Eastern Europe", "North America", "South America", "Middle East & Africa", "Asia", "Austrdlasia"

private static String roles[] = n e w Strinq[] { "Java Developer", "Director/CEO", "Manager", "Sales Person", "Office Worker", "Industrial/Manufacturing Worker"

1;
private UserManager userManager;
( )

public R e g i s t r a t i o n C o r ! t r o l l e r S e r v l e t public void init0

{ )

/ / Crear el U~erManager, utili~ado para almacenar/recuperar informaci6i-Ide usuario / / en/desde la base de datos. ( ) ; userManager = riew UserMar~ager

1
public void doGet(HttpServ1etRequest request, HttpServletRespor~se response) throws ServletExceptiorl ( har~dleRequest (request, response) ;

public void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException { handleRequest(request, response);
/ / Conduce todas las si~licitudes a1 subsistema d e registrs. public void handleRequest(HttpServ1etRequest request, HttpServletResporlse response) throws ServletExceprion { String requestUR1 = r e q u e s t . g e t R e q u e s t U R I 0 ;

try i if

(requestUR1.indexof ("register") i = 0 ) { registerNewUser ( r e q u e s t , r e s p o n s e ) ; ] else if (requestURI.indexof ("regFormSubmit") >= 0 ) { d o N e w R e g i s t r a t i o n ( r e q u e s t , r e s p o n s e ); ] else if (requestUR1.er~dswith ("1og~l.n") ) { 1 o g i n E x i s t i n g U s e r ( r e q u e s t , respon;e) ; ] else if (requestlJRI.indexOf ["loyinFormSubmit") ? = 01 { doLoginUser(request, response); 1 else if (request~JRI.indexOf("displayDetails")>= 0 ) ( d i s p l a y E x i s t i r ~ g U s e r D e t a i l s ( r e q u e s t ,r e s p o n s e ) ; ] else if (requestUR1.indexOf ("disp1a~AllfiegisteredUsers") >= 0 ) { displayAllRegistered1Jsers(request, response); ] else if (requestURI.ir~dexOf("allRegisteredUsers.xml") >= 0 ) ( createAllRegisteredUsersXMLDo~urner~t(request, response);

Escribir aplicaciones JSP con bibliotecas de etiquetas


1 else if (requestUR1.indexof ("displayRegisteredUserHobbies' ) >= 0 ) 1
]

displayRegisteredUserHobbies(request, response); else { response. sendError (HttpServletRespor~se. S C NOT FOUND) ;

I
]

catch (Exception e x ) J, ex.printStackTrace0; throw new ServletException("An error occurred har~dling request:", ex);

1
/ / Registra un punto d e entrada de nuevo usuario. public void registerNewUser(HttpServ1etRequest request, HttpServletResponse response) throws ServletException, IOException [ request. setAttribute ("user", new User ( ) ) ; request.setAttribute("regions", regions); request .setAttribute ("rolesS', roles); RequestDispatcher rd = qetServletContext ( ) .getRequestDispatcher ( " / r e g i s t r a t i o r ~ / r e q F o r r njsp") . ; rd. forward (request, response);

I
/ / Registra un r~uevo usuario utilizando 10s detalles de la solicitud. public void doNewRegistration(HttpServ1etRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException { User user = new User (request.getparameter ("userr~ame" ) ) ; user. setForename ( r e q u e ~ t ~ g e t p a r a r n e t( e" rf o r e n a m e )) ; user. setsurname (request.getparameter ("surname" ) ) ; user.setEmailAddress(request.getParameter("emai1Address") ) ; user. setCompanyName (request.getparameter ("companyName") ) ; user. setMainHobby (request . getparameter ("mainHobby") ) ; user.setPassword(request.qetParameter("password")); user. setRegion (request.getparameter ("region')) ; user.setRole(request.getParameter("r01e") ) ; user.setFavoriteWebSiteURL(request.getParameter("favoriteWebSiteURL") ) ;

try

J,

]
I

SimpleDateFormat d f = r~ew SimpleDateFormat ("dd-MMM-yyyy") ; user. setDate0fBirth ( r e q u e s t . g e t e r( d a t e 0 f B i r t h ) ! = null ? d f .parse(request.getparameter ("date0fBirthr') ) : null ) ; catch (ParseException ex) J, user. setDate0fBirth (null) ;

try i userManager.registerNew1Jser(user); request. setAttribute ( "user", user) ; serveUserCookie ( u s e r , response) ; getServletContext ( ) .getRequestDispatcher ( " / r e q i s t r a t i o r ~ / t h a n k y o u .jsp") . include ( r e , ~ u e s t , response) ; ] catch ( L I s e r r ~ a r n e A l r e a d y C h o s e n E x c e p t i o r e ~x ) [ RequestDispatcher rd = qetServletContext ( ) .getRequestDispatcher ( " / r e g i s t r a t i o r ~ / t r y . A r ~ o t h e r ~ J s e r r ~ a jsp") me. ; r d . forward (request, response) ;

1 1

// sirve el

c o o k i a d e u c u a r i o p a r a u s u a r i o s que s e han r e g i s t r a d i i ii han e n t r a d o . p r i v a t e v o i d serveUserCookie (User u s e r , HttpServletResponse resporcse) { r e s p o n s e . a d d c o o k i e ( n e w C o o k i e (IJSER COOKIE NAME, u s e r . s e r i a l i z e T o S t r i r ~ g ( )) ) ;

/ / R e g i s t r a un p u n t o d e e n t r a d a d e u s u a r i o y a e x i s t e n t e . p - r b l i c v o i d loginExistingUser(HttpServletRequest r e q u e s t , HttpServletResporise response ) throws S e r v l e t E x c e p t i o n , IOException { RequestDispatcher rd = getServletContext() .getRequestDispatcher ( " / r e g i s t r a t i o r ~ / l o g i r ~ F o r m js . p") ; r d . forward ( r e q u e s t , response) ; 1
/ / R e g i s t r a un u s u a r i o e n e l s i s t e m a d e r e g i s t r o . public void doLogir~User( HttpServletRequest request, HttpServletResporlse response) throws ServletException, IOException, SQLException { try i u s e r ]user = userManager. l o g i n ( r e q u e s t . g e t p a r a m e t e r ("username" ) , request. getparameter ("password")) ; serveUserCookie(user, response); response s e n d R e d i r e c t ( " /j spTagApps/registratior~/displayDetails" ) ; 1 c a t c h (NoSuchUserExceptior~e x ) { RequestDispatcher rd = getServletContext ( )

.getRequestDispatcher("/registration/noSuchUser.jsp");
rd. forward ( r e q u e s t , r e s p o r ~ s e; )

I
1
// //
MAS mktodos p a r a manejar s o l i c i t u d e s : d i s p l a y E x i s t i r ~ g U s e r D e t a i l s , displayAllKegisteredUsers e t c .
etc.

N o se preocupe si no entiende por completo la tarea del servlet controlador en esta fase. Analizaremos el c6digo y desplegaremos la aplicacibn mis tarde. El constructor crea una instancia de una clase UserManager. La clase UserManager es utilizada para almacenar y recuperar informacion de usuarios registrados en y desde una base de datos. De nuevo, esto seri analizado en la seccidn de despliegue. Lo interesante de esta parte es el metodo handleReques t ( ) . Contiene las "reglas" que hemos analizado, para asociar solicitudes a las piginas JSP invocadas. Podemos ver c6mo 10s URL mostrados en el diagrama anterior son asociados a sus correspondientes piginas JSP. Por ejemplo, c6mo /registration/ register es asociado a1 metodo regis terNewUse r que configura algunos datos (usuario, roles y regiones) y despues 10s envia a / regis t ration/regForm. j sp,que muestra el formulario de registro. Veamos ahora las otras piginas JSP de la aplicaci6n.

La pagina de formulario de registro


Como nuevo usuario, el primer paso dentro de un sistema de registro es grabar alguna informacion sobre el usuario. En nuestra aplicacion, puede conseguirlo mediante la opci6n uno de la pigina de bienvenida o directamente via http://localhost:800O/jsp/ragApps/registration/register.

Escribir aplicaciones JSP con bibliotecas de etiquetas


El servlet controlador asocia la solicitud a un formulario para introducir detalles del nuevo registro, regForm. j s p , a continuation:
< % @ p a g ei r n p o r t = " j a v a . u t i l . %> < % @ p a g ei m p o r t = " j a v a . t e x t . S i r n p l e D a t e F o r m a t "
+ "

%>

<

% B r i n g i n t h e HTML H e l p e r t a g l i b r a r y % > < % @ t a g l i bu r i = " / h t m l " p r e f i x = " h t r n l V $ >

< j s p : useBean

id="usern type="writinyj sps. registratior~.TJser" scope="request" />

<html> <head>

<title>ReqistratinnC/title>
</head> <body\ <font face="arial, font>

helvetica"

size="4"

color="#996600

< h t m l : f o r m r n e t h o d = " p o s t " a c t i o n U R I = " ./ r e g F o r m S u b m i t " > < t a b l e border="On> <tr> < t d W J s e r Name: < / t d , <td> < h t m l :t e s t I r t p u t name="userr,arne" value="<%= user.getUsername ( ) % i n r1umberOfColumns="20" / > </ t , j >

< / t I-,
<tr> < t d > F i r s t Name: < / t d > <td> <html:textIr~plut r~ame="forerlame" value="<%= user.getForename ( ) r~umberOfColumns="20" / > </td'.

%>"

</tr> < tr >


< t d > L a s t Narne:</td> <td> <htrnl:textInput r~ame="surname" value="<%= user.getSurriarne ( ) r~urnberOfColumns="20" / > </ t d >

%>"

</tr> <tr> <td>Email:</td> <tdi <htrnl:textInput

name="ernailAddress" value="<%= user.qetEmailAddress() r~umberOfColumr~s="30" />

%>"

</td> </tr> <tr> < t d > D a t e Of B i r t h : < b r > ( e .g 01-Jan-1965) </td> <tdi <html: t e x t l n p u t narne="ciateOfBirthn

Capitulo 12
value='<%= new SimpleDateFormat ("dd-MMM-yyyy") . format (user.getDate0fBirth ( numberOfColumns="20" / >

) )

%>'

</td> </tr> <tr> <td>Region of Origin: <br> (Please choose one) </td> <td> <html: list name=" region" id="aRegion" items='<%= ( O b j e c t[ I )request .getAttribute ("regiorls") % > ' i t e m T y p e = " j a v a . lang.String"> <option value="<%= aRegion % > " > < % = aRegion %></option> </html: list> < / td> </tr> <tr> <td>Company Name: </td> <td> <html: textInput n a m e = " c o m p a n y N a m e " value="<%= user.getCompanyName ( ) % > "
numberOfColurnris="20"/>

<br> </td> </tr> <tr> <td>Your Role: </td> <td> <html: list name="role" i d = " a R o l e W items='<%= ( O b j e c t [ I )request . g e t A t t r i b u t e ("rolesS') % > ' i t e m T y p e = " j a v a . lang.Strir~q"> <option value="<%= aRole % > " > < % = aRole %></option> </html:list> </td> </tr> <tr> <td>Main Hobby:</td> <td> <html: textInput name="mainHobby" value="<%= user.getMainHobby ( ) % > " numberOfColumns="30"/> </td> </tr> <tr> <td>Favorite Web Site URL: </td> <td> <html: textInput n a m e = " f a v o r i t e W e b S i t e U R L W value="<%= user.getFavoriteWebSiteURL() % > " r~umberOfColurnns="30" / > </td> < / t r> <tr> <td>Password:</td> <td> <html:passwordInput name="password" r~umberOfColumr~s="20" /><br> </ td> </tr> <tr> <td>Cortf irm Password: </td> <td>

Escribir aplicaciones JSP con bibliotecas de etiquetas

El formulario ofrecido recoge informaci6n ~ t i sobre l el usuario. La p6gina JSP incorpora inicialmente una biblitoteca de etiquetas ayudantes HTML:
< % - Rrlng

<%@taglib

in t h e HTML Helper tag library % > uri="/htmln prefix="htmln % >

Encuentra entonces el bean de usuario de registro, creado por el servlet controlador de registro antes de que esta pigina fuera invocada:

Las propiedades del bean de usuario son asociadas a1 formulario de registro utilizando etiquetas de la biblitoteca de etiquetas HTML importada. Las razones para ello y las ventajas de utilizar etiquetas para el formulario HTML son analizadas exhaustivamente en la siguiente secci6n. La siguiente captura de pantalla muestra el formulario de registro servido:

1
II

Registration
User Name Fkst Name. Last Name
BuftyTheVamp~re Bufty Vamp~re [~he~od~e@trans~lv com ania 01-Jan-1 965

Emad
Date Of Buth (e g 01-Jar-1965) Regon of O w (Please choose one) Company Name Your ole

II]
11

I Eastern Europe
/slayers Inc

ol rector/^^^
Slay~ng Vamp~res

I11
11

Mam Hobby
Password Confirm Password.

Favonte Web Slte URL h t t p . / W yahoo com

1-

Capitulo 12
Desviemonos un poco y estudiernos las ventajas de utilizar etiquetas JSP para el rnanejo de forrnularios HTML y las etiquetaes utilizadas en este ejemplo.

Etiquetas para el manejo de formularios HTML


El empleo de informaci6n de entrada de usuario en piginas Web HTML se consigue con las etiquetas < f o r m > , < i n p u t > , < s e l e c t > y < o p t i o n > . Si sus piginas Web estin basadas en su totalidad en HTML, estas son pricticarnente las unicas opciones a su alcance para introducir datos a traves del navegador. Las alternativas podrian incluir el uso de Applets o Java WebStart en su aplicaci6n. En casos en 10s que el cliente necesita permanecer ligero y 10s tiempos de carga son un problema, estas alternativas quizis no sean la mejor opcion. La etiqueta HTML < i n p u t >es pricticamente una etiqueta general, donde el tip0 exacto de componente de entrada requerido es especificado utilizando un atributo type, como t y p e = " t e x t I p a s s w o r d I c h e c k b o x I image I b u t t o n . . . ".Elusodelaetiqueta<input>requiereel uso correcto de atributos para el tip0 de entrada desplegada. Con frecuencia es dificil recordar q u i atributos pueden ser utilizados con un deterrninado tip0 y su significado deseado. Por ejemplo, s i z e representa el numero de caracteres visibles para una entrada de texto, per0 el numero de pixeles para una entrada de imagen. N o existe ningun atributo que especifique que un campo de entrada requiere una entrada y no existe validaci6n o aplicaci6n del tip0 de datos introducidos; el usuario puede dejar pasar o no cornpletar un campo o introducir datos de caracteres en un campo destinado realmente a la entrada de valores numkricos. En tales casos, 10s carnpos < i n p u t > del formulario con valores potencialmente no vilidos son enviados de vuelta a1 servidor para su procesamiento. Parte de la validaci6n inicial ejecutada por la aplicaci6n en el servidor comprueba la introducci6n de la informaci6n de 10s campos obligatorios y la correcta escritura de todos 10s campos requeridos. Estas ~ o m ~ r o b a c i o nson e s realizadas directamente, antes de que pueda ejecutarse cualquier validacidn especifica de la aplicaci6n o entre 10s diferentes carnpos. Los valores no vilidos o ausentes significan que el formulario original de entrada seri enviado de vuelta a1 cliente para su revision. Nuestras guias de disefio nos dicen que la 16gica de ernpresa pertenece a la grada de modelo de empresa del servidor. Pero, ideberia incluir formas bisicas de validaci6n, como requisitos de carnpos obligatorios o seguridad de tipo? En la actualidad, existe a1 menos una capacidad minima de directiva en la rnayoria de formularios de clientes Web. Con la llegada de JavaScript y sus nuevas capacidades de expresi6n regular, 10s clientes capaces de conseguirlo pueden ficilmente ejecutar una validaci6n tan trivial. El uso de etiquetas JSP para la asociaci6n de propiedades bean a carnpos de formularios HTML puede aportar algunas de las ventajas de la validaci6n de lado cliente mediante la generation de c6digo de lado cliente dentro de la rnisma pigina JSP. Esto elirnina esta trivial validaci6n de la aplicaci6n, libera 10s ciclos del sewidor y la aplicacion puede proceder con la validaci6n especifica de la aplicaci6n y la cornprobaci6n de la norma de la ernpresa. En la fecha de edici6n de este libro, no existe ninguna biblitoteca de etiquetas HTML definida dentro de JSPTL. Sin embargo, existe mucha actividad generalmente en esta irea y en repositorios de fuente abierta en la Web. Una vez rnis, debemos tener cuidado con la cantidad destinada a una biblitoteca de etiquetas consistente en etiquetas ayudantes HTML. Demasiado poco y llegaremos a una situaci6n con esfuerzos duplicados para alcanzar conceptos triviales como entrada de campo obligatoria en el cliente o formateo de entrada. Demasiado y veremos un "robo" de ldgica de tip0 de empresa desde la gads de modelo de aplicaci6n a las vistas de cliente. Conseguir el equilibrio perfecto es siempre la clave. O t r o punto que debemos mencionar, mientras examinamos las directrices de "lo correcto y lo incorrecto" de las piginas JSP, es el tema de la generaci6n de anotaci6n HTML en las etiquetas JSP. Corno regla bisica general, tener etiquetas que generan HTML no es probablemente una buena idea; las capacidades de

Escribir aplicaciones JSP con bibliotecas de etiquetas


manipulaci6n, concatenaci6n y manejo de strings de Java son bastante limitadas y costosas, y generar HTML vincula dichas etiquetas a JSP que generan 6nicamente HTML. Sin embargo, al considerar lo que intentamos conseguir con una biblitoteca de etiquetas ayudantes HTML, el objetivo es generar anotaci6n de forma HTML sencilla. La biblitoteca de etiquetas HTML, escrita por y utilizada en nuestra aplicaci6n de registro, es muy sencilla. Su objetivo es reemplazar directamente 10s elementos HTML <form> y <input>. Sin embargo, la implementaci6n de metodos de validaci6n de forma utilizando JavaScript en el cliente va mis alli del alcance de este capitulo. La siguiente tabla muestra las etiquetas que componen la biblitoteca de etiquetas HTML. Puesto que son tan numerosos, no hemos incluido 10s detalles y atributos. Etiqueta
form text Input name, value, required, disabled, readonly, numberOfColumns, description, tabIndex, accessKey, onFocus, onLoseFocus, onselect, onchange

Atributos

Descripci6n Equivalente aunelemento HTML<f ram>. Equivalente a un elemento HTML <InPUT type="textW . . .>. Observe que Esta etiqueta tiene un atributo required . Si tiene validacibn, podria emplearse JavaScri t en el cliente para garantizar la entracfa del cam o de entrada generado. La validacidn ue& conseguirse mediante directivas de laio cliente invocadas por 10s mitodos onFocus ( ) , onLoseFocus ( ) , onselect ( ) o onchange ( ) . Equivalente al elemento HTML <input type="passwordn

name, value, required, disabled, readonly, nurnberOfColumns, description, tabIndex, accessKey, onFocus, onLoseFocus, onselect, onchange name, value, required, disabled, readonly, numberOfColumns, description, tabIndex, accessKey, onFocus, onLoseFocus, onselect, onchange

. . .>.

Observe que Esta eti ueta tiene un atributo required.Si hay vjidacidn, podria emplearse JavaScri t en el cliente para garantizar la entracfa del carnpo de entrada generado. Equivalente a un elemento HTML <input type="textU . . .>. Observe que Esta eti ueta tiene un atributo required. Si hay v j i d a c i h , podria emplearse avaScri t en el cliente para garantizar a entra a del campo de entrada generado. Si se emplearan expresiones regulares y JavaScr~pt en el cliente, la entrada de este campo podria restringirse aun patr6n de n6mero entero.

cf

La tabla continia en la prigina siguiente

Capitulo 12
Etiqueta Atributos Descripci6n

name, value, required, Equivalente un elemento HTML <input type="text" . . .>. disabled, readonly, numberofColumns, description, tabIndex, Observe que Esta eti ueta tiene unatributo accessKey, onFocus, required. ~ihayvali~i6n,podriaemplearse onLoseFocus, onselect, JavaScript en el cliente para garantizar la onchange entradadel campo de entrada generado. Si se emplearan ex resiones regulares y JavaScript en el cliente, entrada de este campo podria restringirse a un patr6n de nhmero real.

Pa

name, showBothValues, value, required, disabled, readonly, numberOfColumns, description, tabIndex, accessKey, onFocus, onLoseFocus, onselect, onchange

N o existe un elemento HTML equivalente directoparavalores booleanos de entrada. Este etiqueta genera etiquetas<s el ect> y <option> para crear el componente de entrada. Observe que Esta eti ueta tiene un atributo required. Si ha v a l i ~ a ~ i 6 n , ~ o d r i a e m ~ l e a r s e ~ava~cr en i~ eltcEente paraare urar laentrada del campo de entrada genera%o. Si re emplearan ex resiones regulares y JavaScript en el cliente, a entrada de este campo podria restringirse a un patr6n de numero real.

list

id, items, itemType, name, allowsMultiple-Selections, disabled, tabIndex, onFocus, onLoseFocus, onchange, visibleRows

Una etiqueta de lista que facilitala generac16n de HTML < se1ect> con etiquetas <option> especificados e integrados. Itera elementos de tipo itemType, permitiendo la creac16n de una lista de elementos HTLM <option>. Equivalente a un elemento <input type="radioW

radioButton

name, value, label, valueAndLabe1, required, checked, disabled, tabIndex, onFocus, onLoseFocus, onchange name, value, label, valueAndLabe1, required, checked, disabled, tabIndex, onFocus, onLoseFocus, onchange

. . .>.

Observe que el valor y la etiqueta del b o t h de opci6n generado puede ser especificado por separado como value y label,o juntos comovalueAndLabe1. Equivalente a un elemento HTML <input type="checkboxW . . .>. Observe que el valor y la etiqueta del b o t h de opci6n generado puede ser especificado por separado como value y label,o juntos comovalueAndLabe1.

checkbox

Aparecen muchos etiquetas en la tabla anterior. Para mostrar el uso de todos ellos, necesitariamos mucho mis que este capitulo. Como estas etiquetas envuelven principalmente a sus equivalentes HTML,el modo mis sencillo y mejor para demostrar su uso e impact0 dentro de una aplicacih Web seria mostrar cdmo son utilizados en nuestra aplicaci6n ejemplo de registro, regForm.j sp:

Escribir aplicaciones JSP con bibliotecas de etiquetas


< % @ p a g ei m p o r t = " ] a v a . t e x t . S i r n p l e D a t e F o r m a t "
<%- B r i n g

%>

l n t h e HTML H e l p e r t a g l i b r a r y % > <%@taglib url="/htrnlW prefix="html" %>

c h t r n 1 : f o r m r n e t h o d = " p o s t " actionURI="./regFormSubrnit"> < : t a b l e border="rJ"> <tr> < t d > U s e r Name: < / t d > <td> < h t r n l : t e x t I n p u t name="usernarne" value="<%= user.getUsername 1 ) r~urnberOfColumns="20" / > </td> </tr>

%>"

El formulario de registro, r e g F o r m . j s p , utiliza las etiquetas f orm, t e x t I n p u t , p a s s w o r d I n p u t y l i s t de la biblioteca. Cuando se envia el formulario, el senlet controlador de registro procesa el formulario y realiza una comprobaci6n con el nombre de usuario elegido. Si un usuario con el nombre elegido todavia no existe, almacena 10s detalles del usuario en la base de datos del usuario y reenvia a1 nuevo registrado a la pigina "gracias". Si el nombre de usuario elegido ya esti resenado, el controlador de registro reenvia a una pigina de error de registro, consecuentemente. La pigina de agradecimiento y la pigina de error de registro son analizadas en las dos siguientes secciones.

Capitulo 12

Gracias por registrarse


Una vez registrado el usuario, aparece una pigina de agradecimiento. C o m o se podria esperar, la pigina t h a n k y o u . j s p es realmente bastante pequefia y, sin embargo, introduce un concepto muy valioso en las paginas JSP. Se trata de u n concepto que n o aparece con demasiada frecuencia en las plginas Web (en realidad, n o con la suficiente frecuencia). Empecemos examinado el codigo JSP:
< % @ p a g ei m p c r t = " w r i t i n g j s p s . r e g i s t r a t i o r ~ . + " % >

<%- Load

t h e r e s o u r c e bundle fiir t h e page # > <ilPr,:resoi~rceBur~dle r,ame="writirigjsps.registratior~.Registratinr~Resourzes">


< % Display t h e g r e e t i n g message, i r ~ s e r ~ i r tt qh e u s e r p r o p e r t i e s % > < i l Y n : m e s s a g e r , a m e = " g r e e t i r ~ g M e s s a g e " a r g 0 = " < % = u s e r .g e t f o r e n a m e ( ) % > " a r g l = " < % = u s e r . g e t L l s e r n a m e ( ) %>" / > < b r >

<body> p>Thanks

for

reqlsterlnq l'br>

<p>Be s u r e t o c h e c k o u t y o u r u s e r p r o f i l e b y < b r > c l i c h i r ~ g < a href="displayDetails">here</a>. < p i I n t h e m e a r i t i m e , h a v e f u r l w o r k i n g w i t h JSP t a g l i b r a r y <p>Many t h a n k s , < b r > <br> E v e r y o n e a t Wrox P r e s s L t d . < b r > < a href="h~tp://www.wro~.c~m">ww~.wrox.com</a><br> .:hr>
< % Sh:>w t h e d i s c l a i m e r n o t i c e f r o m < i l E n : s t r i n q name="appDisclaimer". &copy; W r ~ xP r e s s L t d , 2001 </ilEn:string;>

applications.

the

bur,dle % >

A primera vista, la pigina parece l o suficientemente inofensiva. Pero el Area decisiva ha sido
internacionalizada. La plgina importa una biblioteca bisica de etiquetas para la internacionalizaci6n, escrita para demostrar el concepto de este capitulo. Incidentalmente, mientras tratamos el tema de internacionalizaci6n, la abreviatura utilizada comfinmente en el mundo de la tecnologia de la informaci6n es i18 (internacionalizacion: i seguido de 18 caracteres, m i s una n). DespuCs de haber registrado a una personalidad aleatoria, la pigina t h a n k y o u . j s p ha sido mostrada, como aparece en la siguiente pantalla:

Escribir aplicaciones JSP con bibliotecas de etiquetas

Dear Bu@, you have been assigned a usemarne of BuffyTheVampire Thanks for registering!

Be sure to check out your user proble b y


cliclung here.

In the meantime, have h workug with JSP tag library applications.


Many thanks. Everyone at W r o x Press Ltd.

vmw.wr~x corn .

We t r y our best to ensure your ~rformation is


kept secret. Ultimately though, w e can't b e held responsible.

La internacionalizacidn ha sido conseguida en esta JSP utilizando lotes de recursos Java. Como quizis rnuchos lectores de este libro no sepan mucho sobre lotes de recursos, a continuacidn repasaremos 10s conceptos bisicos. DespuCs, perfeccionarernos este ejemplo viendo cdmo funcionan las etiquetas en esta pggina.

Internacionalizaci6n de nuestro codigo JSP


La internacionalizaci6n de nuestras aplicaciones se ha convertido en algo rnucho 1116s evidente debido a Internet. Con cualquier persona capaz de acceder a nuestras aplicaciones, desde cualquier lugar del rnundo, la necesidad de ofrecer informacidn al usuario en su propio lenguaje, o adaptado de alguna forrna a sus gustos o preferencias culturales, se convierte en algo muy importante. Sin embargo, una vez mjls Java sale al encuentro de este reto. De repente, con el uso de 10s lotes de recursos, ( java .util .ResourceBundle) en nuestra aplicacidn, el tema de la internacionalizaci6n no parece tan delicado. Con la atenci6n de Java prestada a 10s detalles sensibles a localismos y su aplicacidn en 10s lotes de recursos, la capacidad para adaptar aplicaciones a clientes especificos se consigue sin esfuerzo y casi de forrna gratuita. Repasemos ripidarnente c6mo funcionan 10s lotes de recursos y veamos despuks c6mo pueden ser utilizados de forrna efectiva dentro de una aplicacidn JSP.
GQue e s un lote de recursor?

Un lote de recursos es simplernente un repositorio para una serie de recursos. De hecho, un lote de recursos puede considerarse un conjunto de pares de valor nombre.

Capitulo 12
A un lote de recursos se le otorga un nornbre denorninado nombre base. Por ejernplo, si todos 10s recursos para una aplicacion estuvieran contenidos solo en un lote (probablernente no en una gran aplicacion), podria llarnarse~y~pp~esourc Sin e s embargo, . nornbres especificos de lugar pueden ser adjuntados a1 nornbre base del lote para crear rnis lotes, especificos de cada lugar. Por ejernplo, podriarnos crear:
0 MyAppResources

Por lo general, 10s nornbres de lugar tienen la forrna, < l a n g u a g e > - < c o u n t r y > , con un lenguaje y region opcional de alli donde se utiliza el lenguaje. Por ello, por e j e r n p 1 0 , ~ y ~ p pources-fr-CH ~es especifica recursos en franc& contenidos enMyAppResources, hablados en Suiza yMyAppResources-fr solo especifica generalmente recursos en franc&, sin tener en cuenta donde se utiliza. Los lotes de recursos son irnplernentados corno clases Java o corno archivos . p r o p e r t i e s , con nornbres corno 10s ejernplos rnostrados arriba. Rernitase a la referencia API Java 2, Standard Edition para encontrar detalles especificos referentes a la clase R e s o u r c e B u n d l e .
Como se localizan lor lotde recursos

En esta section, estudiarernos c6rno son localizados 10s lotes de recursos y corno son utilizados con una aplicaci6n. Las busquedas de lotes de recursos son realizadas partiendo de:

o El localisrno deseado del cliente


O El localisrno actual por defecto tal y corno es devuelto por L o c a l e . g e t D e f a u l t de una aplicaci6n Web, este seria el lugar del servidor.
0 El lote raiz de recursos, cuyo nornbre es el nornbre base elegido.
()

. En el caso

Vearnos un ejernplo. Considerando nuestros recursos, identificados por el nornbre base MyAppResources, si el localisrno deseado por el usuario es deterrninado corno -fr-CH (French Switzerland) y el lugar por defecto en el servidor en -en-GB (English - United Kingdom), entonces el orden de busqueda para recursos dentro de 10s lotes seria el que rnuestra el siguiente diagrarna:

Escribir aplicaciones JSP con bibliotecas de etiquetas

sens~ble a 1 lugar

MyAppResources

lote de recursos Baselraiz

lote de local~smo porDefecto

lotes de local~srno
Deseado

El mas sens~ble al lugar

En otras palabras, el localismo deseado por el usuario es Suiza franc6fona por lo que la bGsqueda es de recursos franceses, preferiblemente tal y como se expresan y utilizan en Suiza. Pero, si 10s recursos especificados en 10s lotes franceses deseados no existen, pruebe entonces 10s lotes del lugar por defecto. D e nuevo, si 10s recursos de 10s lotes de lugar por defecto no se hallaran, retroceda entonces hasta el lote raiz de recursos, cuyo nombre es el nombre base elegido. La busqueda se realiza jerirquicamente.

Aplicar lotes de recursos a aplicaciones JSP


Ahora exarninaremos c6mo el concept0 de lotes de recursos puede ser aplicado de forma efectiva en aplicaciones JSP. Inicialmente, veremos algunos etiquetas para abstraer lotes de recursos y despuks volveremos a la pagina "gracias" de la aplicaci6n de registro y veremos c6mo han sido empleados. Hemos creado una biblitoteca de etiquetas de internacionalizaci6n para demostrar lo ficil que pueden llegar a ser las aplicaciones de internacionalizaci6n. Como hemos mencionado anteriormente, en Java es bastante sencillo. Sin embargo, hasta ahora, poco ha emergido en la definicidn de JSPTL en cuanto a la biblitoteca de etiquetas de internacionalizacion. Cuando sea incluida, se basari en principios muy similares a 10s descritos aqui. Las etiquetas de la biblioteca de internacionalizaci6n son 10s que aparecen en la siguiente tabla:

Etiqueta

Atributo

Descripci6n
Carga unRes o u r c e B u n d l e y loponeadisposici6n dentro del alcance del cuerpo de su etiqueta.

name

El nombre base cualificado completo del lote de recursos a emplear. Por ejemplo, com.wrox.writingjsps.il8n. .MyAppResources. La tabla continka en la prigina siguiente

Capitulo 12

Etiqueta

Atributo locale

Descripci6n El localismo a emplear para bhsquedas de recursos en el lote de recursos. Si no es especificado, dependiendo del valor del atributo u s e C l i e n t L o c a l e , se utilizarienlocalismodel cliente solicitante o el localismo por defecto. Determinasi emplear o noel localismo delcliente, si es detectado con Cxito, para bhsquedas dentro del lote de recursos cargado. El valor por defecto es t r u e . Devuelve elvalor de unapropiedad especificada en el lote de recursos en contexto.

useClientLocale

string name alt

El nombre de la ropiedad en el lote de recursos cuyo valor debe ser Bevuelto. Unvalor alternativo para ser utilizado si la pro iedad especificada no pudiera ser encontrada en el Pore de recursos. Espec~ficar un valor para este atributo implementari retroceso, evitando el lanzamiento de excepciones en el caso de que no pudieran hallarse recursos. Proporcionar un cuerpo la etiqueta comovaloralternativo tambienpuedeutilizar elmismo mecanismo de retroceso. Devuelve elvalor de unapropiedad especificada en el lote de recursos en contexto como un mensaje, formateado por la clase j a v a . t e x t . M e s s a g e F o r m a t .Losargumentos arael formato demensajesonespecificadosutilizando fos atributos a r g s o a r g < n > o mediante etiquetas descendientes inrnediatosmessage~r g.

message

name alt

El nombre de la propiedad del lote de recursos, cuyo valor debe ser devuelto. U n valor alternativo a ser utilizado si la ropiedad especificada nopudiera hallarse en el lote e recursos. Especificar unvalor araesteatributo implementari un retroceso, evitanlo el lanzamiento de excepciones en el caso en que no se encontraran 10s recursos. Proporcionar un cuerpo a la etiqueta como valor alternativo tambikn puede utilizar el mismo mecanismo de retroceso.

args

U n array que contiene 10s argumentos. Una etiqueta de argument0 de mensaje. Debe ser utilizado como un descendiente inmediato del etiqueta de mensaje. Los argumentos serin sustituidos en el mensaje en el orden de aparicion de las etiquetes<me s s a g e A r g > bajo la etiqueta progenitor de mensaje. Por lo que el siguiente mensaje
<il8n:messagename="greetingMessage"

a r g O = " < % =u s e r . g e t F o r e n a m e ( ) % > "


argl="<%=user.getUsername()%>"

/>

Escribir aplicaciones JSP con bibliotecas de etiquetas


Atributo
Podria escribirse utilizando la etiqueta <messageArg>:

value

El valor del argumento.

Veamos ahora cdmo ha sido introducida la internacionalizaci6n en el ejemplo de registro y en la pigina thankyou. j sp.Puesto que una aplicacion de registro se asienta abiertamente en cualquier sitio Web, es realmente bastante conveniente que una aplicacion de este tip0 sea internacionalizada, con el objetivo de Hegar a la mayor proporcion de pbblico. Despues del registro de 10s usuarios, estos son reenviados a la pigina de agradecimiento, como hemos visto anteriormente. La pdgina simplemente toma parte de la informacion del usuario de un bean User,la utiliza para dar las gracias al usuario por registrarse y le proporciona una par de vinculos para reenviarle a otras ireas de interis. El codigo para la pigina JSP ya ha sido mostrado. La pigina utiliza la etiqueta ResourceBundle para cargar el lote de recursos nominado, writingjsp. registration. ~egistration~esources,ene~a~cance.Lo~ueestosignificaesque cualquiera de las etiquetas de internacionalizaci6n puede ser entonces utilizado dentro del alcance de Esta etiqueta y de su(s) lote(s) cargado(s). Podemos ver que hay una etiqueta de mensaje que carga un recurso, greetingMessage y proporciona el nombre del usuario y el nombre de usuario elegido como parimetros para el mensaje. Mis abajo, podemos ver cdmo la etiqueta string ha sido utilizado para cargar y mostrar una nota de salvedad que podria, perfectamente, ser especifica de la region en la que se ubica el usuario. Esta en manos del diseiiador de la aplicacion especificar el numero de regiones internacionales que serdn cubiertas y proporcionar lotes para aquellos localismos bajo el nombre base especificado. Para nuestros propositos, crearemos 10s siguientes lotes de recursos:
1. writing. jsps. registration.RegistrationResources . p r o p e r t i e s , q u e c o n t i e n e l a siguiente informacion:
g r e e t i r , g M e s s a g e = H i { 0 } , y o u 1 ( r e userrlame i s { 1 ) ! a p p D i s c l a i m e r = N c > s e s f o r z a m o s a 1 mdximo p a r a q u e su i r l f o r r n a c i b r ~ < b r > o s hacerrios s e m a t e n g a e n s e c r e t o . P e r o , e n l i l t i m a i n s t a n c i a , r ~ in ~ responsables.

2 .writingj sps . registration.RegistrationResources~en.properties;estearchivo


no tiene nada que ariadir a1 lote base.
3.writingjsps.registration.RegistrationResources~en~GB.properties,que

contiene la siguiente informacion:

4.

greetingMessage=Dear

101,

you h a v e

beer,

assigned

usernarrie

of

{l)

writingjsps.registration.RegistrationResources~en~US.properties,que

contiene la siguiente informacion:

Capitulo 12

5.writingjsps.registration.RegistrationResources~fr~properties,quecontiene~a

siguiente informacibn: Cotnenzando desde la parte superior, el listado rnuestra el lore (base) por defecto ( I ) , seguido por 10s lotes de recursos en inglis (2), inglislReino Unido (3), inglCslEstados Unidos (4) y francCs (5). El contenido de cada tote esri especificado despuCs de cada uno de ellos. Sblo queda demostrar el efecto.de diferentes localismos en el cliente solicitante y servidor. El localismo del Sistema Operative y, por lo tanto, del servidor, puede ser canibiado en Windows 98/NT/2000 a travis del icono Panel de Control I Configuraclon Regional. Si estl utilizando Microsoft Internet Explorer (IE) 5.x, puede alterar 10s idiomas aceptados por el cliente via Herramientas I Opcionesde Internet 1 Idiomas...Para u s u ~ r i o s de Netscape, vaya a Preferencias, seleccione la seccibn Navegador, haga clic en la opcion ldiomas y seleccione el idioma que desee. La siguiente captura de pnntalla rnuestra 10s resultados derivados de ejecutar nuestro servidor Tomcat en el localismo English/GB y configurar despuCs I E con Francks como idiorna preferido:

Edicmn

Ver

Favorites

Henarnier

Bonjour Robert! Thanks for registem! Be sure to check out your user profile by clickng &.

In the meantime, have hn wor!ung wth JSP tag library applications


Many thanks, Everyone at Wrox Press Ltd.

We try our best to ensure your dormation is kept secret. IJItimately though, we can't be held responsible

El lote de recursos en francis ha sido elegido y cargado automiticamente porque el navegador ha reflejado 10s deseos del usuario (en realidad, a travis la cabecera HTTP accept-languages) para el contenido en francCs. Puesto que el lote franc& habia ignorado la propiedad greetingMessage, Cste ha sido elegido y utilizado desde ese lote. Sin embargo, el tote francis no ha proporcionado una propiedad de salvedad especifica ni tampoco 10s lotes por defecto de ingles local o inglks/Gran Bretafia del servidor. Esto significa que esta propiedad debe residir en el lote base; de no ser asi, puede suceder un error. La propiedad estaba presente en ese lote y ha sido cargada desde ahi.

Escribir aplicaciones JSP con bibliotecas de etiquetas


Como eiemplo a inglCslEstados . - final, si cambiamos ahora nuestro localismo preferido del navegador Unidos, la siguiente captura de pantalla ilustra el resultado:

II

Hey Herschel, you're now known as KmstyTheClown! Thanks for regstenng! Be sure to check out your user profile by clickmg b. In the meantme, have hn w o r h with JSP tag hbrary applications.

II

IIII

Everyone at Wrox Press Ltd


~ ~ : a corn r ~ x

Subject to US export and Data Protection policies.

Estos resultados reflejan claramente el hecho de que el lote de localismo ingl6slEstados Unidos invalida 10s mensajes greet ingMes s age y appDis claimer, especificamente para clientes regionales de Estados Unidos.

La pagina de error de registro


Si, durante el proceso de registro, se elige un nombre de usuario que coincide con el nombre de usuario de un usuario existente, el servlet controlador de registro reenvia al usuario a la pigina de error de registro. El c6digo para la plgina tryAnotherUsername .j sp es realmente muy sencillo y es el queaparece a continuaci6n:

<html? <head> ititle>Registration Errors</title> </head> <body> <p>Sorry, t h a t u s e r n a m e w a s a l r e a d y


and <a h r e f = " # "

taken.

P l e a s e g o b a c k i n your b r o w s e r
another username</a>.

o n c l i c k = " w i n d o w . h i s t o r y . ~ o ( - 1) " > c h o o s e

</body> c/html>

Los resultados de intentar registrarse como miembro ya existente son 10s que mostramos en la siguiente captura de pantalla:

Arch~vo Edicih ~ireccitm


-

Ver

I& http //localhost 8110WlapTag4pps/reg1stratm~/regForrnSubrn~t L]


-

Favorltor
-

Herramientas

Ayuda

. ,m
&r
I

Sorry. tkat username was already taken Please go back in your browser and c110osp :mther U C ~ ~ X L I ~

En este punto, podria elegirse o t r o nombre de usuario volviendo al formulario d e registro. ~ s t ha a sido la secci6n dedicada a las plginas de registro. Volvamos ahora al registro en el sitio.

La pagina de formulario de entrada


Cuando 10s usuarios se registran en un sitio Web, se espera de ellos norrnalmente que elijan un nombre de usuario y una contraseria. Esta inforniaci6n es utilizada siempre que vuelven al sitio Web.

Ya hemos visto el formulario que recoge esta y otra informaci6n en nuestra aplicaci6n de registro. Los
usuarios registrados entran en el sistema utilizando la opci6n dos de la plgina d e bienvenida, o directamente via http://localhost:8000/jspTagApps/registration/login. El servlet controlador asocia la solicitud d e entrada a la JSP formulario d e entrada, 1 o g i n F o r m . j s p , que aparece a continuaci6n:

Igual que el formulario de registro, esta JSP formulario de entrada importa y utiliza la biblitoteca d e etiquetas ayudantes HTML para crear el formulario d e entrada y 10s campos d e entrada. En este ejemplo, el n6mero d e caracteres visibles para cada campo ha sido establecido en 20, la siguiente captura d e pantalla muestra el formulario d e entrada servido:

Escribir aplicaciones JSP con bibliotecas de etiquetas

Arch~vo Ed1c16n Ver


I

FavwRos

Herramlentas

Ayuda

[hmchIfl

hltp l/localho:t 20001r~pTag4pp.;lr~ilr Irahonllogn

"m
81r

El formulario de e n t r a d a , l o g i n ~ o r m j . s p , utiliza las etiquetasf o r b t e x t I n p u t , p a s s w o r d I n p u t de la biblitoteca de etiquetas H T M L . Hernos analizado estas etiquetaes en la liltima secci6n. C u a n d o se presenta el formulario, el servlet controlador de registro procesa 10s elementos del formulario y s e asegura de que Ins credenciales del usuario son vilidas y de que existe un usuario con el nombre d e usuario y la contraseiia especificada en la basc de datos de registro. Si las credenciales del usuario son verificadas, el servlet controlador sirve un cookie d e usuario. El cookie persiste entre solicitudes a la aplicaci6n de registro y autentifica al usuario de la aplicaci6n en cada solicitud posterior. Despues de que el cookie sea servido, el controlador envia al usuario a la pigina que rnuestra el perfil d e usuario. Si 10s detalles introducidos n o corresponden a 10s d e un usuario registrado, el servlet controlador reenvia al usuario una pigina d e error d e entrada. Las piginas de perfil de usuario y dc error d e entrada son analizadas en las siguientes secciones.

Ver su perfil de usuario


Las aplicaciones de registro de sitios Web perrniten a 10s usuarios registrados v e r y potencialmente, editar sus detalles dc registro. Aunque dentro el alcance d e este libro, la aplicaci6n de registro d e este capitulo n o perrnite carnbios e n la i n f o r r n a c i h de registro, si ofrece la posibilidad de ver 10s detalles d e registro existentes.
Los usuarios que s e han registrado, corno hernos visto e n la Gltima seccibn, pueden ver su perfil de usuario a traves d e la opci6n tres de la pigina inicial o directarnente via http://localhost:800O/jspTagAppsl registration/displayDetails. El servlet controlador asocia la solicitud para el perfil de usuario a d i s p 1 a y D e t a i l . s . j s p . Esta JSP rnuestra la informacibn de usuario autentificada. El c6digo para la JSP es el siguiente:

Capitulo 12

<body> <font face="arial, helvetica"

size="4" color="#996600">User Profile</font>

<table b o r d e r = " O W > <t r> <td>User Name:</td><td><%= user.getUsername() %></td> </tr> <t r> <TD>First Name: </td><td><%= user. getForename ( ) %></td> </tr> <t r> <td>Last Name: < / td><td><%= user .getSurname ( ) %></td> </tr> <tr> <td>Email:</td><td><%= user.getEmailAddress() %></td> < / t r> <t r> <td>D.O.B.:</td><td>Cfr~d:dateFormat date="<%= user.getDateOfBirth() % > " format ="dd MMMM, yyyy" / > </td> </tr> <End: number id="ageThisYearW value="<%= new Date() .getyear( 1-user.getDateOfBirth() . g e t Y e a % > " / > <tr> <td>Age This Year:</td><td><%= ageThisYear %></td> </tr> <tr> <td>Actual Age: </td><td><%= user. getAge ( ) %></td> < / t r> <fnd: boolean id="isPensioner" value="<%= ageThisYear. intvalue ( ) >= 65 % > " scope="REQUEST" / > <t r> <td>Pensioner This Year:</td><td><%= isPensioner %></td> </tr> <t r> <td>Region of Origin: </td><td><%= user .getRegion ( ) %></td> </tr> <tr> <td>Company Name:</td><td><%= user.getCompanyName() %></td> </tr> <t r> <td>Your Role: </td> <td><%= user.getRole ( ) % > <jx:if test="$user.role == 'Java Developer'" > <img src="images/duke 30x29. jpg" alt="Duke o f Java" align="middle"> </jx:if> < / td> </tr> <tr> <td>Main Hobby: </td><td><%= user.getMainHobby ( ) %></td> </tr> <t r> <td>Favourite Web Site:</td> <td><%= user.qetFavoriteWebSiteURL() %>&nbsp; <a href='serverSideIncludePeek. j sp?url= <fnd:encode><%= user .getFavoriteWebSiteURL( ) %></fnd:encode>'

Escribir aplicaciones JSP con bibliotecas de etiquetas

Este c6digo ha generado la pigina de perfil dc usuario de muestra que vemos en la siguiente captura de pantalla:

User Profile
KrustyThe Clown TJser Name: Herschel First Narne: Krustofsky Last Name: Krusty@XrustyTheClown. corn Ernail: 01 January. 1965 D.O.B.. 36 Age This Year: 36 Actual Age: false Pensioner Thls Year North Amenca R e ~ o of n Or'i Krusty Brand Enterprises Company Name: Director/CEO Your Role: Endors~ng commercial products Main Hobby: h t t p : / / w . y a h o o .corn Click Here to Peek1 Favousite Web Site Last Accessed Account: 20-Aug-2001 15:15:18 GMT+01:00

A primera vista, esta pigina parece realizar muchas funciones. Cuando se realiza una solicitud a esta piigina, el servlet controlador autentifica al usuario, crea un bean User para albergar propiedades del usuario y pone este bean a disposicidn de la pigina JSP en la solicitud. Esta pigina localiza y utiliza el bean
User:

Capitulo 12

Esiste una serie de scriptlets para extraer las propiedades de usuario para ser mostradas por la plgina JSP:

Examinemos lrls etiquetas utilizadas en la pigina. La pigina irnporta la biblitoteca de etiquetas j x, desde la JSPTL y utiliza la etiqueta i f desde esa biblioteca para probar si el rol del usuario es "Java Developer". Si lo es, una imagen de Duke (de Java) es insertada en la pigina, al lado del rol mostrado. Esto se ha logrado gracias al siguiente fragment0 de c6digo:

Como Krusty n o es un Desarrollador Java, el imagen no ha sido ariadida a la pigina. Se utilizan otras etiquetas dentro de la p l g i n a d i s p l a y D e t a i l s .j s p . Estas etiquetas son descritos en la siguiente seccion.

Algunas ideas fundamentales sobre etlquetas en JSP


La pigina de vista del perfil de usuario, d i s p l a y ~ t e a i l s j s p , ha utilizada la etiqueta condicional de JSPTL i f . Pero tarnbien ha utilizado otras etiquetas, escritos para esta aplicaci6n, para demostrar algunos conceptos comunes en JSPs. Yo denomino las denomino etiquetas fundamentales o de fundamento. Una biblioteca de este tipo a l b e r g d a etiquetas que serian utilizadas en nunlerosas JSP basadas en aplicaciones Web. La pigina JSP ha importado la biblitoteca de etiquetas de fundamento con la directriz t a g l i b :

Volviendo a las partes de la pigina JSP que hemos destacado, podemos ver que las etiquetes n u m b e r , b o o l e a n , d a t e F o r m a t y l o g han sido utilizados todos desde esta biblioteca (todos estaban precedidos por el prefijo de la biblitoteca de etiquetas de la pbgina). La siguiente tabla presenta una breve descripci6n de las etiquetas deesta biblioteca:

Escribir aplicaciones JSP con bibliotecas de etiquetas

Etiqueta number

Atributo

Descripcion Declara una variable de directiva numerica y le asigna opcionalmente un valor. Especificaen nombre deunavariable de directiva que debe ser creada para re resentar el n h e r o . El atributo i d tiene un significaSo especial cuando re utiliza con etiquetas ue crean variables de directiva. Remitase a la especi?icaci6n de JSP para mis detalles.

Value

El valor inicial del numerico. Puede ser una constante numerica, tipo primitiva o envoltorio de tipo s h o r t , i n t e g e r , l o n g , f l o a t , o d o u b l e . Elvalor defect0 es cero. El alcance de la variable: igina, solicitud, session o aplicacidn. Valor por d e i c t o , alcance de pigina. DeGara una variable de directiva booleana y le asigna opclonalmente un valor.

scope Boolean
id

El nombre de lavariable de directiva que debe ser creada. El valor inicial de la variable booleana: true o false. Valor por defecto, f a l s e . El alcance de la variable: igina, solicitud, session o aplicaci6n. Valor por dezcto, alcance de pigina. Produce una representation de string de una fecha, formateada de acuerdo con el parimetro especificado f o r m a t para el localismo y lazona horaria especificada.

Value scope dateFormat

date format

El j a v a .u t il . at eque debe serespecificado. El formato a adoptar por la representaci6n de string de la fecha. Esti basado por complete en 10s patrones proporcionados por la clase j a v a . t e x t . S i m p l e . ~ a t e ~ o r menlaplataforma at Java 2 Standard Edition. produciria salida Por e'emplo, "aaaa.MM.dd hh:mm:ssW dela/orma"l99~.10.02 15:10:25"y"EEE,MMM d,yyyyf' produciria salida de la forma "Mlerc, Agosto 19, 1998".

timezone

El nombre de una zona horaria conocida. Especificada para contrarrestar la hora en una zona horaria especifica y proveer el tiempo de ahorro de luz del dia. U n l o c a l e es utilizado ara sensibilizar el formateado de lafecha aun localismo Beterminado. sine especificado, seutilizaellocalismo preferido porlos clientes, sles posible; si no, se utiliza el localismo por defecto del servidor. Registra su cuerpo o mensaje especificado utilizando el API Servlet Logging.

locale

109 message throwable encode

Especifica el mensaje que debe ser registrado. Especificaun j a v a . l a n g T h r o w a b l e paraser registrado. Una etiqueta que codifica en URL su cuerpo. Remitase alaclasej a v a . n e t . URLEncoderparamis informaci6n.

Capitulo 12
Las etiquetas de declaracidn, n u m b e r y b o o l e a n , proporcionan a 10s autores de JSP u n rnodo f k i l de declarar y utilizar variables de directiva en sus piginas JSP. Esto resulta especialrnente fitil, en la declaracion de variables en scriptlets JSP, cuando el autor de la pigina no es necesariamente un experto en Java o para la creacidn de variables de directiva cuyo alcance va rnis alli del de la pigina JSP en la que son declaradas. La etiqueta n u m b e r crea una variable de directiva nurnerica sin prestar rnucha atencion a1 tip0 nurnkrico explicito. D e hecho, debido a que Esta etiqueta esti basado en el tip0 j a v a . l a n g . Number, puede representar 10s valores de cualquier prirnitiva numerica o tip0 envoltorio de primitiva. Este es u n ejernplo tornado de la pigina de presentacidn del perfil de usuario:
< % @ p a q ei r n p o r t = " j a v a . u t i l . * " % > < % @ p a g ei r n p o r t = " w r i t i n g j s p s . r e g i s t r a t i o n . * "
%>

<frd:ro~rnber id="pageStar-tTirneV v a l l ~ e = " < % = Systern.currer~tTimeMillis ( ) %;." <j s p : u s e B e a n i d = " l J s e r l ' t y p e = = " w r i t i r ~ s gp j s . reqistratii11r1.IJser" sc~:~pe="request" />

/>

'bdy><ftr,r,t

f a c e = "a r i a l ,

hel'jetica"

size="4"

ct>lor="#996600"?User P r o f i l e < / f o r ~ t >

< t a b l e border="On> ctr> 'td>User Narne:</td>ctd><B= u s e r . g e t i l s e r n a n i e ( ) </tr?

%></td\

... ...

frd:rturnber id="ageThi.sYear" v a l u e = " < % = new D a t e ( ) . g e t y e a r ( ) - u s e r . g e t L 3 a t e O f B i r t h ( ) . g e t Y e a r ( ) <tr> <td>Age T h i s Y e a r : i / t d > < t d > < $ = ageThisYear % \ < / t d > </tr> <tr> <td>Actual Age:</td><td>i%=u s e r . g e t A g e ( ) % > i / t d >

%>" / >

</ t r?
<fnd:boOlean id="isPensloner" value="<%= aqeThisYear.intValut(i scope-"REQUEST" / > Year:</td><td><%=ispensioner %></td>

>= 6 5

'a>''

i t r > <td>Pensior,er This </tr>

... ...
</table?

... ...

</body> </htrnl>

Podemos ver, en la parte resaltada de la seccidn anterior, que una variable de directiva, a g e T h i s Y e a r , es creada e inicializada en la edad, este aiio, del usuario cuyos detalles estin siendo rnostrados. La etiqueta b o o l e a n crea una variable de directiva de tip0 Booleano y le asigna un valor inicial. El ejernplo anterior crea la variable Booleana, i s p e n s i o n e r , este valor es producido como parte de la inforrnaci6n de usuario. Estas etiquetas de declaracion y lo que con ellos se logra son bastante auto explicativos.

Escribir aplicaciones JSP con bibliotecas de etiquetas


La capacidad para forrnatear ripida y efectivarnente una fecha, sin tener que crear objetos Da t e F o r m a t en scriptlets JSP, puede conseguirse utilizando la etiquetadat e ~ o r m a tLa . pigina JSP ha utilizado la etiqueta para forrnatear la fecha y la hora en la que el usuario accedi6 por ultirna vez a su cuenta. Esto se ha logrado con una facilidad relativa, si lo cornpararnos con la cantidad de c6digo necesaria en un scriptlet JSP para conseguir el rnisrno resultado, que reproducirnos a continuaci6n:

Las otras dos etiquetas utilizadas en la JSP de perfil de usuario son l o g y e n c o d e . La etiqueta l o g ha sido utilizado para producir el tiernpo de generaci6n de la pigina, en rnilisegundos, para el registro del servidor. Hasta el lanzarniento de Java SDK 1.4, el rnanejo de registro no estaba incorporado corno elernento estindar en 10s API de Java. La etiqueta log sirnplernente registra su rnensaje a traves del rnttodo ~ervlet~ontex t g . El lugar a1 que se dirigen 10s rnensajes registrados es especifico del servidor. lo Generalrnente van a parar a 10s registros estindar o u t o e r r del servidor Web. En el caso de la J ~ E E - ~ ~ ~ ~ % \ l o g s \ < s e r v e r > \ ~ e b \ c a t a< ld ia nta e. >.log. Irnplementaci6n deReferencia,vana%

< C o n q u t frecuencia necesitarnos codificar en URL 10s URL de nuestras piginas JSP? D e hecho, cualquier text0 que contenga caracteres reservados, ya sea en URL o en el cuerpo del docurnento HTML, debe ser codificado. La etiqueta de codificaci6n ha sido utilizado para conseguirlo rnis ficilrnente que si utilizdrarnos, por ejernplo, j a v a . n e t . URLEncode todas y cada una de las veces. La etiqueta ha sido utilizado para codificar el URL favorito del usuario:
< t d > F a v o u r i t e Web S i t e : . / t d > x t d > < % = user.getFavoriteWebSiteURL( 1 % > & n b s p ; < a href='serverSideIr~cludePeek.jsp?url= < f r ~ de :r i c o d e > < % =u s e r . g e t F a \ i o r i t e W e b S i t e U R L ( ) % i \ / f n d : e n c o d e > ' target=="inANewWir~dowPlease">Click Here t o P e e k ! < / a > </td>

La pigina de perfil de usuario es servida a 10s usuarios que entran con txito. Analicernos ahora q u t sucede en nuestra aplicaci6n de registro cuando falla la entrada.

Pagina de error de entrada


Si se ha introducido en la entrada un nombre de usuario o una contrasefia n o vilida, el controlador de registro reenvia a la pigina de error de entrada. El c6digo para la pigina n o s u c h u s e r . j s p es bastante corto y es el que le rnostrarnos a continuaci6n:

<htrnl> <head<title;.Loqin E r r o r s < / t i t l e i </head' \body> y o u h a v e e n t e r e d arj i n v a l i d [User Name . ~ r Passwi~sd.<br> <''Sorry, a" g? ai t rr,y '/ai. <br> P l e a s e < a h r ~ f = " j/ s ~ T a g A p p c / r e q i s t r a t i ~ r ~ / 1 i ~ ~ q i r ~ </body> </htmlX

El resultado de un intento de entrada corno usuario n o registrado es el que se rnuestra en la siguiente captura de pantalla:

Capitulo 12

Pxchivo
t

Ed~cinn Ver

Favorh
-

Herramlentas
-

Ayuda
. -

~irecci6n

I&

http //lmdho ,t 800011spTa~~pps/rrgtslral~on/IognForrnSuhn~t


--

$1'

Sorx-1, you have entered an ~nvatd Usernarne or Password Please t ~ f l .


-

2_1 Listo

Ver el sitio Web favorito del usuario


La pigina de perfil del usuario, presentada en la ultirna seccibn, proporcionaba un vinculo con el que visar el sitio Web favorito de un usuario registrado. Decimos visar porque no proporciona un vinculo direct0 n1 sitio Web. En su Iugar, el vinculo proporcionado es el de otra pigina dentro de la aplicacibn de registro. La pigina JSP, llamada s e r v e r s i d e I n c l u d e P e e k . j s p , incluye el contenido del sitio directamente en el lndo servidor y lo retransmite de vuelta al cliente, en la respuesta. Para conseguir esto, la pigina utiliza una etiqueta include de lado servidor (SSI), s s i . La pigina JSP tieneel siguiente listado:

El vinculo Click Here to Peek en la pigina de Perfil de Usuario ejecuta la pigina s e r v e r S i d e I n c l u d e P e e k .j s p . La misnla pigina, el concept0 incluir de lado servidor y la e t i q u e t a s s i son examinados en la siguiente seccion.

Server-Side Includes (SSI)


La especificacibn JSP nos proporciona una serie de mecanismos convenientes y litiles para incluir contenido en piginas JSP. Para el contenido estitico, incorporado en el periodo de traducci6n. podemos utilizar In directriz incluir de la forrna siguiente:

Los archivos incluidos con esta directriz son incorporados en el periodo de compilaci6n o en el de traduccion. Una vez incluidos, forman una parte integrante de la JSP que contiene la directriz i n c l u d e . El contenedor JSP t a m b i b analiza el contenido incluido de esta forma. Para la inclusi6n de contenido dininlico (es decir, contenido que debe ser incorporado en el periodo de solicitud), podemos utilizar laaccidn estindar incluir:

El contenido incluido de este niodo es incorporado de la misma manera que el n16todo i n c l u d e ( ) de la c l a s e ~ e q u e s t ~ i s p a t c h eobtenido r, a travCs de una llarnada a

Escribir aplicaciones JSP con bibliotecas de etiquetas


S e r v l e t C o n t e x t . g e t R e q u e s t D i s p a t c h e r ( ) .Sinembargo,enambosm~todosinclude mostrados, el U R I especificado en el archivo o pigina incluidos deben ser relativos a la aplicacidn Web que ejecuta la inclusi6n.

Hay ocasiones en las que quizis sea mis conveniente incluir contenido en piginas JSP en el period0 de solicitud, desde fuera del alcance de la actual pigina Web. D e hecho, hay casos en 10s que esta es la finica opcion. Por ejemplo, si el contenido que debe ser incluido ha sido generado fuera de la aplicaci6n mediante otro proceso.

En la actualidad, no existe ninglin mecanismo proporcionado en la especificacibn JSP para realizar la inclusibn de contenido que no sea originario de la jerarquia del documento de la aplicaci6n JSP.
Sin embargo, el concept0 de incluir de lado servidor permite la inclusi6n de contenido en el lado servidor desde el interior de la jerarquia del documento de la aplicacidn Web, o desde fuera de ella. El contenido incluido desde fuera de la jerarquia del documento de la aplicaci6n Web tiene que ser incluido dinamicamente. Por ello, la idea de SSI puede parecer interesante pero, como la mayoria de 10s paradigmas en el desarrollo de Tecnologias de la Informaci6n, tiene algunas limitaciones y concesiones. Describiremos estos inconvenientes en la siguiente seccion.

Algunos temas relacionados con Server-Slde Includes


Incluir contenido en el lado servidor puede degradar el rendimiento del senidor Web. Pero, si cachetizamos 10s datos, entonces el rendimiento debe mejorar, iverdad? Si cachetizamos 10s datos en el servidor, icon que frecuencia debemos renovarlos? Hay temas de disefio e implementation relacionados con las inclusiones de lado servidor, que incluyen 10s siguientes puntos:
0

Rendimiento en el servidor. Demasiado contenido incluido en el extremo servidor,


dinimicamente, podria en d t i m a instancia degradar el rendimiento del servidor.

Cachear datos durante mucho tiempo podria provocar un desfase del contenido. C o n la memorizaci6n en cache del contenido que cambia con frecuencia se corre el riesgo potencial de s e n i r datos desfasados a 10s clientes. Esto plantea inquietudes: "idebemos cachetizar datos dinimicos?; si lo hacemos, idurante cuinto tiempo?". Purgar datos cacheados cuando falla la actualizacibn de solicitudes. Si se realizan solicitudes periddicas para actualizar contenido en cache y alguna o todas esas solicitudes fallan, ipurgamos el contenido potencialmente desfasado y lanzar un error de aplicacidn, o debe la aplicaci6n obtener 10s datos de la memoria cache? Por lo general, la aplicaci6n debe continuar de forma normal y puede que las solicitudes posteriores para actualizar la memoria cache sean eficaces, per0 n o siempre ocurriri asi.

CI Proporcionar una alternativa o retroceso. Para el contenido que pueda necesitar ser incluido regularmente o que puede que n o siempre sea recuperable, debe haber un mensaje alternativo para mostrar a1 cliente.
Todos estos temas deben ser tratados a1 considerar el uso de SSI en piginas JSP. Encontrar el equilibrio perfecto puede significar la diferencia entre un servidor con capacidad de reaccidn, que parece servir el ultimo contenido, o un senidor perezoso que tiende a servir contenido desfasado o a fallar regularmente si n o se puede encontrar el contenido.

Capitulo 12
En la siguiente section, demostraremos cdmo las inclusiones de lado servidor pueden ser incorporadas a una pigina JSP utilizando una etiqueta personalizado.

Una etiqueta Server-Side Include


La etiqueta incluir de lado servidor ( s e r v e r - s i d e I n c l u d e ) mostrado a continuacidn puede considerarse una alternativa a una acci6n estindar i n c l u d e , que sdl0 se diferencia en que permite a1 URI identificar un recurso que puede residir en el interior de la jerarquia de documentos de la aplicacidn Web (el comportamiento estindar dentro de piginas JSP) o fuera de ella. Sin embargo, no se realiza ningun esfuerzo por implementar la cach6 de lado servidor de contenido incluido. La etiqueta s s i y sus atributos son descritos en la siguiente tabla: Etiqueta Ssi Atributo Descripci6n Una etiquetainclude puede incluir contenido estitico o dinimico, dentro o fuera de la aplicacidn JSP que ejecuta la inclusibn. uri El URI, relativo oabsoluto, del recurso que debe ser incluido. El recurso debe tener un tip0 de contenido de base textual, como text/html. Un Booleano que determinado si debe lanzarse cualquier excepcion que intente i n c h el recurso debe ser lanzada fuera de la pigina JSP en la que se ha incluido el recurso. S i t h r o w s ~ r r o re s s t rueyselanzaunaexcepci6nprocesando i n c l u d e , se invocara u n a e r r o r p a g e especlficadautilizando la directrizpage. Si t h r o w s E r r o r s es false y la etiquetas i tiene un cuerpo, el cuerpo de Esta etiqueta es evaluado y producido como conten~do para la lgma JSP que ejecuta la inclusi6n. En efecto, retroceso es similar al atributo alternativo este mecanlsmo ( a l t ) utilizado en elementos HTML. Valor por defecto, false.

throws Errors throws Errors (continued)

Be

Volviendo al perfil de usuario, el vinculo Click Here to Peek referencia a la plgina s e r v e r S i d e I n c l u d e P e e k j s p . Haciendo clic en el vinculopara visar el sitio Web, elvinculo abre otra ventana que muestra 10s resultados de s e r v e r S i d e I n c l u d e P e e k j s p , como muestra lasiguiente captura de pantalla:

Escribir aplicaciones JSP con bibliotecas de etiquetas

Yahoo!

Fantasy Faorhall - s w u p taday for the 2001 season

. , .-,'

S h q ,-71r1rms Alriils ~:>.ds~!.f~!l~ ,:A:~,I"E 1 1 x 1 \'rll~svPcs Media wrWuotes. h. & o ~ I $ LT1c&5 Connect Cv_rs~ C I j a \ l%i,>s + ;:' n':rlv: 'Gnrrtu~; -h l d Xtn1h115 ),I ~ ~ c c n .z ? 11ih110 ~ t - P m o n d 5 P _ r ~ l r X c l.h Fl11?taP e l r o d .-,,hir Ec~c~f: - R r ~ c i ~ i ~~ se ? ~ ~ l -I~ ll rr il u ~ , ? , ' P-vDir.rj Fun G ~ L : b& L!+wicr P.Tbar~v. PI,-110 I" morr...
----

Yahoo! Shopping Thousandsofatoms M l o n s ofproducts

Departments

Scores
Esik- B a w r

Features

E!-$!!.c
' " 3
I
:. t

s l & . , -

[ C C s

F~!:LIL<,:~L">J
~L~?-:,im+r

F~;,TIS

b . 5 : : . Iinh1. ''~~ton< 7.m-l s

~~~~L~~xI!~A~.T

"'"".*'"

m x c ilctlts

n t t r slorrs

--~

. .:*,*:m:+Jfl

Fijese en que nuestra aplicaci6n de registro tiene la capacidad de incluir contenido procedente de cualquier lugar del mundo. D e hecho, utilizar yahoo.com es un buen ejemplo de un sitio cuyo contenido y funcionamiento pueden ser incluidos por terceras partes. Parn conseguir este enfoque d e portlet o subventana, todos 10s vinculos de la pigina inicial deben ser absolutes. Incluso podernos realizar blisquedas en yahoo.com desde la ventana de vistas. El fragment0 de c6digo para serverSideIncludePeek . j s p que realiza la verdadera inclusi6n es el siguiente:

Observe que el cuerpo d e la etiqueta contiene texto alternativo. Este texto sera mostrado si, por cualquier raz6n, el contenido del URI especificado n o pudiera ser incluido. Siemyre es una buena idea incluir algo descriptivo para 10s clientes en caso fallo, c o m o la siguiente opci6n:

Capitulo 12

Sin ernbargo, si el contenido del URI especificado n o pudiera ser cargado y tuviCramos que utilizar una fornia abreviada de este c6digo:

Obtendriarnos el siguiente tip0 de error, que n o resulta muy agradable para el usuario que solicita la pdgina:

)IA Servlet Exception Has Occumd


1
Exception Report
]dVhN.bervlct.SerVleC~xCCpClo~: An
at qt

at

at mc
at

at
at at

st

s t

a
at

at
at

error o c c u r c d durlng I n c l u d e of "hccp:ffuuu.Let~Notl~ndIc.corn": ruu.Lecst4ocTlndIt.com 0rg.~~~~h~.3a~per.rUnLim.Pa~~C0nte~~ImpI.h~dI~Pag~E~~~9c10n~Pm~Cont~~t11pl.~~oi452~ 0r~.~pa~h~.3~~.~O9O2C~~0is~r~tI0n~OOOZL~~~verSi4eIncl~deP~ek~l~p.~J~pSe~vncel~OOO2Cc@alsccat1on~OOO 0rg.apb~h~.~a~per.runrl~.H~CpJ~~R~1e.s~~~1~~IK~c~d~~8~~e.J~v~:107) ]1~a~.servI~c.hCtp.H~CpSer~I~t.se~~I~t~HttpSer~l~c.java:B53l org.au~ht.ja~per.~er~Ier,J~p3t~~I~tSJspSrr~I~tY~~ppe~.~er~1~elJ~p9e~~Iet~y~~a:2OO) crg.b~sc-he.~asvec.aervle~.J~pServle~.osrv1c~J3pFlle~Jspservler.3av~:379) 0rq.~p~he.j~s~tr.scrvlct.JapScrvI~~.~~fvlce[Jsp5~rvlct.java:456) ~ m v m , n ~ v l ~ c . h tH ttp tp3~rvI~t.se~~1~e(h!~r~9e~vI~c.1~vn:853) Or~.spacne.cacalIn~.corc.Appl~carton~rL~erChaln.lntrrn~lDoFllter(IppI1cat1on~rItcrl'haln.~avs:247) or~.apschc.cscrlrna.corr.A~uI~cac1on~llccrChaln.dorll~~rlh~pllcsclonTllcccCha1n.]ava:l93j 0r~.a~~~h~.cmt~Ilna.~0~e.S~~ndardV~~pperVal~t.1nv0II~IS~~ndordVcappecVal~t.]a~a~2431 0r~.spachc.cstaLIna.core.SrandsrdPlpcIlnc.lnvokeNexr(SrasUardPlpcl~nc.~sva:S66) 0rq.ap11~h@.~~c~1lna.c0r~.St~ndardP1ph1t~.lnv~keIsrandaraPipellne.y~1e:+72) ocg.a~achc.catalIna.carc.ConralncrBmac.lnvokt(1TontalncrEalt.Jawr9~31 or~.ap~he.c~talin*,~0r~~3cdnd~rK0nt~~tYsve.lnvoke(scandarbConte~cV11~.j11va:2191

at or~.a~ac~.catallna.corc.3candardPlpsIlnC.LnvokcNexC(S~andardPlgeIln~.jdv~:S66) ac orrr.spschc.c~ral1na.corc.SrandardPip4IIne.lnvokelStandardPlpelrne.jwa:472l at oru.r~uche.c~~nlIna.corc.Concalnerl4.e.1nvokelContalncrBa~c.jsvaz943) at .)r~.b~d~he.~0rallna.corc.StsndsrQConrzx~.lnvoke(BcandardCanteuc.~ava:2251) mt 0r~.b~b~he.cs~aLlna.~0r~.3t~n~rQn0a~Val~~.1nvoke(StandardHoscVa1ve.]ava:164j at O r g . a p ~ h ~ . ~ 0 t a l l n m . ~ o r e . 9 t ~ n d m ~ a P 1 p e I i n e ~ l n ~ 1 0 k e N ~ ~ t l S t d n d m r d P 1 p e 1 ~ n e ~ 1 ~ ~ ~ ~ S 6 6 ~ ar o~g.spb~he.~~CalIn~.v~lvts.Accc~aLo~aIve.invokcIAccer~Lo~slve.]ava'446j at 0rg.~~g~h~,~1~mII~.~~r~.StandardPLpcline.lnv~kctlerc13randmrdPlpelrne.]svn!564) s C 0r~.~~9~he.~1t~l~~.~0re.5tand~rdPlpeli.ln~Okc(JtandardPlptlLnc.]s~:+l2) at org.spsche.ca~allna.cure.Z0nCa1ne~B~1~~invoke(ContalntrB~sr.java:9~1I ar ~ r ~ . s p a c n e . c a r a l l n a . c ~ ~ ~ . 5 t s n d 1 1 ~ d E n ~ I n ~ V a I v ~ . l n v ~ k e ( 5 ~ a n d ~ r d E n ~ ~ n e V ~ l v ~ . 3 m v ~ : l 6 3 l at u r ~ . a ~ a ~ h ~ . ~ a ~ a l ~ n a . c o ~ e . S c a n d s r d P I p ~ I L ~ . l n v 0 k e N e ~ t l S c a n d ~ r d P ~ p e I 1 ~ . ] ~ v ~ : 5 6 6 ~

Escribir aplicaciones JSP con bibliotecas de etiquetas

Administracion: la pagina Mostrar-todos-10s-usuarios


La aplicacion de registro proporcionar algunas funciones utiles de administraci6n. Una de estas funciones es una presentation resumida de todos 10s usuarios registrados. La pigina All Registered Users es seleccionada como opci6n cuatro de la pigina inicial, o directamente como http://localhost:800O/jsp/ TagApps/registration/displayAIIRegisteredUSers. Una vez mis, el servlet controlador intercepta la solicitud, interroga despues a la base de datos para encontrar a todos 10s usuarios y construye un bean de pigina de administracih que contiene una lista de 10s usuarios para ser presentada en la pigina JSP. El controlador asocia el URL / r e g i s t r a t i o n / d i s p l a y A l l R e g i s t e r e d U s e r s p a r a l a J S ~ d e p r e s e n t a c i 6 n , d i s p l a y ~ 1 l ~ e ~ i s t e r e d. ~j ssp. ers

<%@page impnrt="j ava. util.+" % > <%@page i r n p u r t = " w r i t i r q j s p s . r e q i s t r a t i o r ~ .

+ "

%>

<%@taglib uri="/four,dation" prefix="fndM % > <%@taglib uri="http:// java.sur~.corn/jsptl/ea/jx" prefix="jx"%> <%@tagllb uri="http://java.sur~.corn/jsptl/ea/jr" p r e f i x = " j r V % > <j sp: u s e B e a n id="adrnir~PaqeBear~" type="writir,gjsps.r e g i s t r a t i o r ~ . R e ~ ~ i s t r a t i o r ~ A d m i r ~ P a g e B e a r ~ " scope="request" / > <htrnl> <head> <title>All Reqistered Users</title, </head> <boil y> /font face="arial, helvetica" si:e="ln colnr="#C1C16600">All Registered Users</ FONT><br> 0r t ifr~j:ilateFormat forrnat="dd-MMM-yyyy 'at' HH:mm:ss z " > ifnd: c u r r e n t S y s t e r n T i m e M i l l i s / >
</fr~d:ilateForrnat><br>

<br> <j r: c h o o s e > <jr:when test="<%= adrninPqeBean.getReqisteredUsers() .ler~gth == 0 % > " > Currerltly there are no registered users! < / j r:when> <j r:otherwise, <table border="l"> <tr bgcclor="black"> <td><font cnlnr="white">User Narne</font></td> <td><funt cnlor="white">Email Address</font>c/td> <td><fcnt color="white">Last Accessed Accuunti/font></td> </tr> <jx: forEach var="aUserM i t e r n s = " $ a d m i r ~ P a q e B e a r ~ registeredusers" . status="status"> /j x:declare id="aUserM type="writinqj sps. r e g i s t r a t i o r ~ ~ u s e r " /> <tr> itd><jx:expr v a l u e = " $ a U s e r . u s e r r ~ a r n e " /></td> itd><jx:expr value="$aUser.emailAddresss' /></td> itd><fnd:dateForrnat date="<%= aUser. getLastAccessed ( ) % > " format ="dd-MMM-yyyy HH:mrn:ss z" /></td> i/tr> <./ j s : forEach> //TABLE> //jr:otherwise>

Capitulo 12

La siguiente captura de pantalla rnuestra un ejen~plo de 10s resultados esperados de esta pigina:

Archlvo

Edicibr

Ver

Fworitos
. . . .

Herrarrnentas

Ayuda

All Registered Users


on 20-Aug-2001 at 15:31:22GMT+(31:00

BuEjTheVarnpae 'Il~eLodge@transylvamacorn

r--

,20-Au~-LUUl 15 06 10 /Grn+OlOO

c wgurn@pohce spmglield corn 15 09 40


-

20lug-2001

GMT+O 1 00

r-@ Local intrand Examinernos las etiquetas utilizadas en la pigina. La pigina importa Ias bibliotecas de etiquetas j r y j x, desde JSPTL y utiliza una serie de etiquetas de esas bibliotecas: las etiquetaeschoose,when, o t h e r w i s e , f o r E a c h , d e c l a r e y e x p r . Las etiquetaschoose y, posteriorrnente, las etiquetaswhen y o t h e r w i s e , son utilizados para cornprobar si hay o no alglin usuario que mostrar. Como ya hemos mencionado en las secciones que analizaban las etiquetas JSPTL, la etiqueta c h o o s e es el equivalente a la instrucci6n de Java s w i t c h o el bloque i f - t h e n - e l s e i f - e l s e . Aqui lo utilizamos para comprobar si hay o no alglin usuario que mostrar:

Escribir aplicaciones JSP con bibliotecas de etiquetas


\choose> <when . . .no users. . . > / / En la actualidad no hay usuarios reqistrados </when> <otherwise . . .we must have surne users.. . > / / Iterar y mostrar un resumen de usuarios registrados </otherwise> '/chciose>

Ya hemos visto ejemplos que utilizan la etiqueta f o r E a c h . Sin embargo, esta pigina utiliza la etiqueta d e c l a r e para servir de puente entre el entorno de atributo de alcance, utilizado por etiquetas JSP y el entorno de directiva JSP:
<jx: forEach var="aIJser" items="$adminPageBean. registeredUsers" status="status"~ <jx:declare id="aUserM type="writingjsps.registratior~.User" /, <t r> <td><jx:expr v a l u e = " $ a ~ J s e r . u s e r n a m e " /></td> <td><jx: expr value="$alJser. ernailAddressM /></td> <td><fnd :dateForrnat date="<%= aUser.getLastAccessed ( ) % > " format ="dd-MMM-yyyy HH:mm:ss z" /></t.d> </tr>

A medida que la pigina itera la lista de usuarios, se crea una variable de directiva JSP, a u s e r , para cada usuario del ciclo. Ya nos hemos encontrado antes con la etiqueta d a t e F o r m a t en la secci6n sobre la pigina de presentaci6n del perfil de usuario, Ver supropiopefil de usuarto. La etiqueta d a t e F o r m a t utiliza la propiedad 1 a s t A c c e s s e d del bean de usuario, referido por la variable de directiva, para formatear la fecha y la hora en la que accedi6 el Gltimo usuario. U n punto final que debemos destacar es el uso de una nueva etiqueta, currentSystemTimeMillis, utilizado en conjunci6n con la e t i q u e t a d a t e ~ o r m a t :
or l <fnd:dateForrnat format="dd-MMM-yyyy <fnd:currentSystemTimeMillis/i </fnd:dateFormaticbri 'at' HH:mm:ss z">

Esta etiqueta se origina desde la biblioteca de fundamentos, presentada en ejemplos anteriores. La etiqueta es descrito en la siguiente tabla para una mayor claridad: Etiqueta c u r r e n t s y s t emTimeMillis Descripci6n Produce la fecha analizada en milisegundos desde el 1 de Enero de 1970,00:00:00 GMT. Utilizado enconjunci6ncon la etiqueta dateFormat.

El concept0 y uso de la etiqueta c u r r e n t S y s t e m T i m e M i l l i s es sencillo. A1 ser utilizado como el cuerpo de la etiqueta d a t e F o r m a t , proporciona la fecha y hora actual para formateo. Es su funci6n exlcta en el nuestro anterior ejemplo.

Adrninistracion: un servicio Web de base XML


Otra de las piginas de administraci6n proporciona una lista de usuarios registrados como documento XML. En la Dltima seccibn, hemos visto una pigina de administraci6n para ver informaci6n resumida

Capitulo 12
sobre todos 10s usuarios registrados. La plgina analizada en esta secci6n realiza una funci6n similar pero, en lugar de generar una pagina HTML, que enumere 10s usuarios, genera un documento XML que contiene la informaci6n del usuario. Como s61o genera informacion de contenido, independientemente de c6mo se presente la informacion, puede ser utilizado por otras partes de la aplicaci6n de registro o incluso por partes externas que pueden realizar llamadas a este servicio. En la vida real, si la aplicacion de registro tuviera que enfrentarse a un sitio Web real, las partes externas podrian ser clientes terceros que necesitaran saber q u i h ha accedido a1 sitio. Aunque hemos mantenido nuestra aplicaci6n de registro simple en su funcionalidad, estos tipos de interfaz XML son denominados servicios Web. Aunque en la actualidad existe mucho debate sobre 10s modos de registrar estos servicios (quizis utilizando WSDL y UDDI) y las posibles formas de nombrado (quizls utilizando Simple Object Access Protocol - SOAP), 10s servicios XML corrientes y sencillos son, sin embargo, servicios Web. Examinaremos otra parte de la aplicaci6n que hace uso del servicio, en la siguiente secci6n. El documento XML creado no es generado por una JSP. El documento es creado por el servlet controlador de registro y devuelto a1 llamante directamente. El controlador recibe la solicitud para el documento, como indica la siguiente muestra de c6digo de servlet controlador:
public 'loid

createAl1Rogistered~J.-ersXMLDocument ( HttpServletRequest

request, HttpServletResponse respanse) throw- ServletExcept-ion, IOException {

try

t
User

a 1 l U s e r . s [I

1 2 s e r M a n a g e r .f i n d A l I 0 ;
=

UsersToXMLConverter usersToXMLConverter rlew C l s e r s T o X M L C , > r ~ v e r t e (ra 1 1 U s e r s ) ; response. setCont-entType ( " t e z t / x m l " ) ;


)

response.getWriter().write(usersToXMLCor~verter.qetXMLDocumer~t());
c a t c h ( E x c e p t i a r ~e x ) [ tl-irow new S e r v l e t E x c e p t i c ~ , r ~ ( " A u nn e x p e c t e d e r r o l - r ~ c c u r r e d when " " c o n v e r t i r c q u s e r i n f o r m a t i o n t o XML", ex);

El servlet controlador procesa la solicitud encontrando todos 10s usuarios registrados y proporcionando un array de usuarios a una clase ayudante, U s e r s T o X M L C o n v e r t e r , que convierte la lista en un documento XML. Para completar el ejemplo, a continuaci6n tiene el c6digo para la clase UsersToXMLConverter:
package import impcrt imp"rt import irriport import writingjsps. registrati~>ri;

ja v a . i o . ' ;
j avax.xm1. p a r s e r s . D o i ' u m e r ~ t B u i l d e r F a c t o r y ;

ja v a x . s m l . p a r s e r s . D o c ~ ~ m e n t B u i l d e r ; j a v a s . z m l . p a r s e r s . P a r s e r C o n f i q u r a t i o r ~ E x c e pito n ;
o r g . s r r 1 1. s a x . S A X E x c e p t i o n ; org.w3c.,3orn. *;
{

~ ' u k l i cc l a s s UsersToXMLConverter p r i v a t t S t r i r i g xrr11Uoc;

p u b 1 i c U s e r s T o v ~ ~ ~ o n v e r t e ~ - L C r v(eU rts eer users c o n v e r t U s e r L i s t T o X M L ( u s e l - s );

[I

throws

Ezception

Escribir aplicaciones JSP con bibliotecas de etiquetas

p u b l i c S t r i n g getXMLDocurnerjt ( ) r e t u r n xmlDoc;

I
r r i v a t e void c o r , v e r t U s e r L i s t T o X M L ( U s e r u s e r s [ ] ) throws Exception [ D o c i u m e n t B u i l d e r F a c t o r y d h f = D o c u m e r ~ t B u i l d e r F a c t o r y rLewIr1star1ce . ( ) ; D o c u m e n t B u i l d e r d b = d b f . r,ewDocumentBui:der ( ) ; Document d o c = db. newDocument ( ) ; E l e m e n t r n n t N o d e = d o c . c r e a t e E l e m e n t ("USERS") ; rontNode. s e t A t t r i b u t e ("r~urnber", I n t e g e r . t o S t r i n q ( u s e r s . l e n g t h ) ) ; f o r ( i r t t n = 0; rl < u s e r s . l e n g t h ; n t t ) { E l e m e r l t l ~ s e r N o d e = d o c . c r e a t e E i e m e n t ("USER" i ; ~ u ~ e r N o dsee. t A t t r i b u t e ( " u s e r n a m e " , u s e r s [ n ] . g e t 1 J s e r n a r n e ( ) 1 ; u s e r N o d e . s e t A t t r i b u t e I " f o r e n a m e " , u s e r s [rtl . g e t F n r e n a r n e ( ) ) ; u s e r N o d e . s e t A t t r i b ~ ~ (t"e s u r r , a r n e n , i u s e r s [ r ~ .!g e t S u r r ~ a m e ( 1 ) ;

userNo.Je.setAttribute("ernailAddress",
u s e r N o d e . s e t A t t r i b u t e ["mainHobby",

u.-ers[r~].getEmailAddress() );
) ;

u s e r s [ n ] .getMainHubby( )

dnz. appendchild (rmtNodt) ; XMLUocurner~tStrirlqifier xrnlStr-ir~gifier = r,ew X M L D o c u m e r i t S t r i r ~ g i f i e r ("ISO-8859-l", f a l s e , i r n l U o c = x n i i S t r i r j g i f i e r . t v l s t r i n g ( d r i c );

true);

La clase UsersToXMLConverter utiliza el API JAXP 1.1 (el API por defecto, si esti utilizando Tomcat 4) y el API DOM 2.0, para construir el documento y devolverlo como un string al Ilamante. Este servicio es solicitado como opcion cinco desde la pigina inicial o directamente como http:// localhost:8000/jsp/ragApps/registration/allRegisteredUsersxl. La siguiente captura de pantalla muestra un ejemplo de 10s resultados esperados de esta pigina, utilizando IE:

Archivo

Ed&

Ver

Fawitos

Herramientas

Awda

.&.-

=!

. . . :xrl-ll ,

,el ;lun="l.O" encnd1ng="lSO-E85~?-1"! :

- c l G E R S number=%'>
<USER ~ma~1Pddre:s="TheLodge@transyIvania.~om"

forename="Buffq" malnHobby="Slaying Vampires" s?mam~.="Vampire" l~serr~ame="BuFfyTheVampire" : ' : . i?JSEF' emailb.dd!-ei:="c.wiggum~police.springfield.com" farenme="Clancy" tna~nHubb\i="Impersonating Edward G . Robinson" sl.rin~nie="Wigguni" ~~~ernmi~="ChiefWigg ,J':u m " cCISEF: emailAddress="sideshowBoblloonies.org" forename="Robert" riia~nHobby="Plotting kill Bart Simpson" surnarne="Terwilliger" ~lser.tiani~="SideshowBob" ,/::USEF: e111a1lAcl~ji-~s~="Krusty@KrustyTheClown.com" fi2renatne="HerscheIflma~nHobGy="Endorsing c u m m e r d a l products" :umar~ie="Krustofsky" 11se1-natme="KrustqTheClown" / : .;-USER ernallAddres:="TheDetective@BakerStreet.coml' fnrenams="Sherlock n~a~tiHobby="Finding Criminals" ~ l m a m a = " H o l m e s ~~sernarn~="SherlockHolmes" " /'z <USER ema11Addt-e--="Garq@CCLnirm ~ t - Im e = " G a r y " mainHobby="Windsurfing" surnarne="Watson" ~username="Gazzal" /> .-/'USEP'.:

Desplegar la aplicacion de registro


DespuCs de haber llevado a cabo el proceso de construcci6n de la aplicacion de registro, despleguemos la aplicacion en su entorno. La aplicacion de registro y el c6digo fuente esti disponible para su descarga en el sitio Web de Wros, en http://www.wrox.com/. Si no lo ha hecho asi en las secciones anteriores en la JSPTL, descargue todos 10s archivos para este capitulo y siga 10s siguientes pasos para ejecutar la aplicaci6n:

O Ejecutando el servidor de la Iniplementaci6n de Referencin, tome el archivo j spTagApps . w a r y afiidalo a un archivo EAR de la aplicaci6n utilizando la herrarnienta de despliegue:

Escribir aplicaciones JSP con bibliotecas de etiquetas

File Edii Tools Help

il Seleccione el archivo WAR, haga clic en Resource Refs y aiiada una factoria de recursos de tipo

Ble

i0Dll cjl@! $
aF h l ~ s
@ JSPtagWh; @servers P localhost JSPTagsAPP
Q O applrcaflons 9 0 JSPTagsAPP

pl

T_ools Help

Type j~he~l~hara dbclRegI?tfal~onl a w sql D~laSaurceConta . ig


Coded Name -

I I

~ I ~ ~ ~ v V I I !II ~ ~ V I ~ lnr I - ~

Capitulo 12
-1 C r e e la base d e datos d e usuario. Hemos utilizado Cloudscape 3.6 como base de datos en la que

aln~acenar informaci6n d e usuarios registrados. Si todavia n o la tiene, puede descargar la base de datos desde http://www.cloudscape.cornl. La base d e datos para la aplicaci6n ya estl presente en el WAR c o n i o W E B - I N F / d b / r e g i s t r a t i o n D B . El esquema para la base de datos es el siguiente:

Deseari situar esta base dc datos en alglin lugar de su disco duro y referenciarla cuando configure D a t a s o u r c e utilizando la Herramienta de Despliegue. Ln fuente de datos debe tener el nombre JNDI j d b c / R e g i s t r a t i o n puesto que ese serl el nornbre que busque la aplicaci6n (una d e 12s clases en las que n o hemos b u s c a d o , ~ s e r ~ a n a g e r SeleccioneT~olsI ). Server Configuration ... (Herramientas I Configuraci6n del servidor) desde la ventana principal de la Herran~ienta de Despliegue y, en el cuadro de diilogo Configure Installation, (Configurar instalaci6n)configure una fuente de datos estindar que apunte a la base de datos:

3 Inicie la base d e datos Cloudscape mi ~ d b utilizando c el siguiente comando:

Ll Finalmente, soliciteel URL de la plgina inicial de la aplicacibn, http://localhost:8000/jspTagApps/

registration/index.html.

Este capitulo se ha centrado en la escritura de aplicaciones JSP con bibliotecas de etiquetas y, como resultado, la construcci6n d e la aplicacidn de registro se ha centrado ampliamente en las piginas JSP y las

Escribir aplicaciones JSP con bibliotecas de etiquetas


etiquetas que Cstas emplean. Animamos a1 lector a explorar la aplicaci6n j spTagApps, su estructura y las clases que contiene.

Lo que esta por llegar: la biblioteca de etiquetas estandar


Con el lanzamiento de JSP Standard Tag Library (JSPTL), el limite entre etiquetas geniricas y etiquetas personalizadas especificas de la aplicaci6n va a estar mucho mis definido. Conceptos muy genkricos como flujo de control, manejo de fecha y hora, internacionalizaci6n y procesamiento XML/XSLT estarin a cargo de JSPTL. Esto deja en libertad a1 desarrollador de la aplicacion JSP para que pueda centrarse mis en el desarrollo de la aplicacion con bibliotecas de etiquetas centradas en la aplicaci6n. Asi como bibliotecas estandarizadas de etiquetas JSP, JSPTL promete ofrecer lo siguiente: Una definici6n de c6mo las etiquetas interactiian con el entorno. Para etiquetas anidadas o etiquetas que deben ser anidados dentro de otras etiquetas, corn0 estas etiquetas interactGan con sus progenitores. Extensibilidad. Un metodo para extender las etiquetas en JSPTL. Apoyo de lenguaje de expresi6n. Significados adicionales de valores de atributo. Hemos visto muchos de C S ~ O Sen 10s ejemplos presentados en este capitulo. MantCngase a1 corriente del lanzamiento de JSPTL y obtenga las entregas en http://jakarta.apache.org/ taglibs/.

Hemos abarcado muchos temas en este capitulo, examinando las ventajas para desarrolladores, vendedores y empresas de la estandarizacion de las etiquetas mis comunmente utilizados en la actualidad. Hay mucho trabajo involucrado en este proceso en este momento y la presentacion de JSPTL promete ser emocionante y beneficiosa en todo el mundo. DespuCs de leer este capitulo, esperemos que haya adquirido unos conocimientos solidos de algunos de 10s patrones y uso comun de 10s API de Java 2, Standard Edition y Enterprise Edition que pueden ser explotados a traves de un grupo de etiquetas comunes y consistentes. Hemos analizado:
0

Las ventajas de utilizar bibliotecas de etiquetas personalizados

o Algunas de las bibliotecas de etiquetas especificas de vendedores disponibles en la actualidad


0

La proxima presentation de la Biblitoteca de etiquetas Estindar JSP (JSPTL)

DespuCs hemos echado un vistazo a una aplicacion de registro, utilizada a lo largo de todo el capitulo, como ejemplo principal. La aplicacion de registro ha sido construida para utilizar y explotar a1 miximo las etiquetas de prueba tip0 JSPTL descritos en las posteriores secciones. DespuCs de haber presentado el ejemplo principal, hemos examinado varios aspectos del desarrollo cotidiano de JSP, cubriendo las bibliotecas de etiquetas para:

Capitulo 12
0

Etiquetas fundamentales, como 10s de declaration, flujo de control, manejo de fecha y hora, inclusiones de lado servidor y otras etiquetas diversas Internacionalizacion Formas H T M L envoltorio Creacion de vistas X M L de datos contenidas en una base de datos relational

0 0 0

C o n estos conceptos en mente, ya estamos preparados para comenzar a utilizar las etiquetas JSP en nuestras aplicaciones. Est6 pendiente de JSPTL; va a explotar todos estos conceptos y, a1 hacerlo, revolucionari Java y 10s frentes de tecnologias Web. En el siguiente capitulo, vamos a analizar el A P I JavaMail y su uso.

El correo electronico, e-mail, es una de las tecnologias informiticas de redes mis antiguas afin en uso, precediendo a Internet en unos veinte aiios. El mundo vive y respira a ritmo de e-mail: las empresas crecen gracias a su uso, las familias se unen a travks del mismo, practicamente todo el mundo dispone de una direcci6n de correo electr6nico. Sin embargo, puede que le sorprenda saber que, para una herramienta tan fiable, la tecnologia subyacente es relativamente sencilla. El envio y reception de e-mail en Internet nunca ha sido complicado. Consiste en abrir una conexi6n ( o "socket") para establecer la comunicacion, transferir datos y, posteriormente, cerrar la conexibn, todo ello con ayuda de comandos. Por esto se ha convertido en una tecnologia extraordinariamente s6lida. Ir6nicamente, la transferencia real de mensajes de e-mail nunca ha presentado muchos problemas; es la interpretaci6n del contenido del cuerpo del e-mail lo que ha generado tanta confusi6n. Es este aspect0 el que el protocolo Multipurpose Internet Mail Extensions (MIME) ha intentado resolver. Por ejemplo, por medio de un sistema basado en ASCII, ic6mo podriamos transferir un archivo binario como una imagen o un fichero ejecutable de mod0 que el receptor sepa c6mo tratarlo? Es el tip0 de intercambio que se puede conseguir a traves del estindar MIME.
-

El API JavaMail es u n grupo abstracto de clases que posibilitan la implementaci6n de sistemas basados en mensajes. El API JavaMail ha conseguido para el mundo de 10s mensajes lo que JDBC consigui6 para las bases de datos: un mktodo abstracto para interactuar con una amplia gama de almacenamientos de mensajes. JavaMail facilita la incorporaci6n de conectividad de correo electrdnico completa en un programa, senlet, bean o applet Java. Las complejidades asociadas al empaquetado de un e-mail para su recepci6n y entrega efectiva han sido abstraidas para reducirlas a un simple conjunto de llamadas de mktodos. El API JavaMail fue introducido por primera vez como paquete independiente per0 en la actualidad se ha integrado como parte del nficleo del API J2EE. Afin asi, todavia se puede descargar como paquete independiente y utilizarse con aplicaciones fuera del espacio J2EE (como veremos m6s adelante).

Capitulo 13
En este capitulo, analizaremos la logistica del uso de JavaMail para manejar correo electr6nico sin tener que preocuparnos de 10s protocolos subyacentes. A1 finalizar el capitulo, habri logrado: Apreciar y comprender 10s protocolos POP, SMTP e IMAP Describir el uso y las prestaciones de MIME en el proceso de creaci6n de un mensaje Comprender la estructura completa del API JavaMail Instalar y configurar el API JavaMail para aplicaciones que no sean J2EE Enviar un e-mail con y sin anexos Recibir un e-mail manejando anexos donde sea necesario Navegar y utilizar carpetas remotas

Protocolos de correo
Los protocolos compatibles con correo electr6nico estin bien establecidos y son muy s6lidos en este campo. Aunque no es absolutamente necesario, no es mala idea pararse a pensar lo que el API JavaMail intenta abstraer para el usuario. En esta seccibn, examinaremos las implementaciones centrales de protocolo integradas como parte de la distribuci6n de JavaMail:
R Simple Mail Transport Protocol (SMTP)
0

Post Office Protocol versi6n 3 (POP3) Internet Message Access Protocol (IMAP)

A1 mismo tiempo, aunque no se trata estrictamente un protocolo de transporte, examinaremos el protocolo utilizado para empaquetar contenido de correo:
R Multipurpose Internet Mail Extensions (MIME)

Anteriores entregas del API JavaMail no incluian una implementacidn POP3. Para acceder a servidores POP3, tiene que utilizar una implementacio'n de terceros. Como puede imaginar, algunos pensaban que no contar con uno de 10s protocolos ma's comunes era una equivocacio'n por parte de Sun. La &ma entrega de JavaMail (1.2), que esta' especificada como parte de J2EE 1.3, ha rectificado este error.

Simple Mail Transport Protocol (SMTP), propuesto en 1982, es un protocolo disefiado para la distribuci6n de mensajes de correo a servidores. Su resistencia puede atribuirse a su sencillez a la hora de trasladar o transmitir mensajes a 10s servidores. SMTP es meramente un agente de entrega y no se utiliza para leer e-mail. Debido a que SMTP puede actuar como servidor de entrega (es decir, puede entregar e-mail en nombre de otro servidor) ha estado abierto a1 amparo de spammers ("emisores de correo basura"), conocidos por enviar grandes voldmenes de correos no solicitados a 10s usuarios de todo el mundo. Por este motivo, muchos administradores de sistemas han bloqueado o restringido, la capacidad de su servidor SMTP y so10 aceptan correos especificamente dirigidos a la base de usuario del servidor.

JavaMail
Mencione la palabra spam a cualquiera y probablemente sepa de lo que estri hablando, y no m e refiero a la gran cancio'n de 10s Monty Python. Spam es cualquier correo no solicitado y spummers son las personas ( u organizaciones) que generan dichos correos. Para darse a ellos mismos algo de credibilidad, puede que incluso simulen pertenecer a u n respetado dominio distinto del suyo propio. Por ejemplo, utilizando S M T P resulta m u y fricil enviar u n e-mail y hacer que parezca que procede de billgates@microsoft.com. Esta operaci6n se conoce como relaying (reenvio). La mayoria de servidores S M T P comprueban estos correos, pero no siempre. Est6 atento.
Es irnportante tornar nota de estas restricciones sobre la capacidad del servidor SMTP, ya que puede parecer que nuestra aplicaci6n JavaMail no envii correo correctarnente, lo que nos obligari a cornprobar el c6digo en busca de 10s motivos. Si tenemos un problema, probablernente se deba a que el servidor a1 que estamos intentando enviar un correo no es el host del misrno, por lo que sus funciones de reenvio estarin notablernente restringidas. Corno cualquier otro protocolo, SMTP tiene sus limitaciones. Por ejemplo, cuando se cornponen 10s carnpos de cabecera para una transaccidn SMTP, no deben exceder 10s 512 caracteres. Adernis, la parte de datos del rnensaje no debe tener lineas superiores a IOOO caracteres. Sin embargo, no es necesario preocuparse excesivamente por estas restricciones ya que el API JavaMail se encarga de todas ellas. Para encontrar inforrnaci6n adicional sobre 10s aspectos especificos de SMTP, puede acudir a1 documento original RFC#821, disponible en la direccion http://www.rfc-editor.org/rfc/rfc821.txt.

Post Office Protocol (POP) es el mecanisrno utilizado por la mayoria de usuarios para acceder a su correo. Funciona de forma similar a un buz6n convencional y permite a 10s usuarios acceder o descargar su correo, alrnacenarlo localmente y ( ~ ~ c i o n a l m e n telirninarlo e) del servidor. Es entonces responsabilidad del usuario hacerse cargo del correo desde ese momento, archivindolo en algun almacin 16gico. El servidor P O P no ofrece ninguna funci6n de almacenamiento rnis alli del buz6n unico que recibe el nuevo correo. De hecho, puede resultar algo confuso para 10s nuevos usuarios ya que 10s clientes de e-mail de hoy en dia, como Microsoft Outlook, crean la impresi6n de que el servidor esti haciendo rnucho rnis de lo que en realidad hace. La versi6n actual de POP, la 3.0, data de finales de 1988 per0 sus origenes se remontan a 1984. De nuevo, se trata de un protocolo muy bien establecido y su capacidad de resistencia puede atribuirse a la sencillez del conjunto de instrucciones del protocolo. Para obtener rnis detalles sobrei POP3, puede consultar el documento RFC#1939 en http:I/www.rfceditor.org~rfclrfc1939.text.

Internet Message Access Protocol, o IMAP, es un protocolo utilizado por nurnerosos servidores de email de ernpresa; ofrece un conjunto de funciones mucho rnis complete que P O P e incluso que SMTP. Con POP, la premisa es que el usuario es responsable del almacenamiento del correo, mientras que con IMAP el responsable es el servidor. IMAP ofrece una estructura de carpetas para que el usuario interactue con la misma; todos 10s mensajes se almacenan en el servidor sin ninguna necesidad tkcnica de descargarlos en el equipo local del usuario. La principal ventaja para el usuario es que puede conservar todos sus correos en un punto central, independientemente del cliente que utilice para concectarse. IMAP ofrece algo rnis que simples opciones avanzadas de alrnacenarniento aunque tambikn perrnite entregar y buscar correo.

Por el contrario, el almacenamiento de 10s mensajes de todos 10s usuarios supone una gran carga para el servidor, por lo que precisa grandes cantidades de espacio en el disco. Es una de 10s mayores incovenientes del protocolo IMAP y es el motivo por el que organizaciones con una infraestructura de servidor poco desarrollada no lo utilizan. Si el servidor falla, se pierde el correo de todos 10s usuarios, a diferencia de lo que ocurre si solamente falla un finico ordenador cliente, en cuyo caso s61o se pierde el correo de un usuarlo. JavaMail es compatible con este protocolo por medio de su API. Sin embargo, conviene mencionar que muchas de las funciones de IMAP dependen estrictamente del servidor de correo. JavaMail finicamente pasa la solicitud a1 servidor en segundo plano y coteja cualquier resultado. En estos casos, la funcionalidad de JavaMail se asemeja a la de JDBC (JDBC simplemente pasa el procesamiento a la base de datos de segundo piano y realmente no realiza ningfin procesamiento importante por si mismo). Aunque se trata de un protocolo superior a SMTP y POP, IMAP no se utiliza tanto como 10s anteriores, por ello debe asegurarse de que su servidor es compatible con IMAP antes de intentar cualquier comunicaci6n utilizando este protocolo. Es conveniente destacar que la mayoria de servidores de correo disponibles comercialmente incluyen IMAP como parte de la construcci6n estindar (por ejemplo, Microsoft Exchange, Lotus cc:Mail y Eudora WorldMail). En el documento RFC#2060, que encontrari en la direction http:l/www.rfc-edit0r.0rg/rf~/rf~2060.t~t, puede conseguir mas information. A1 mismo tiempo, para conocer las diversas implementaciones de IMAP y 10s servidores de correo compatibles con las misma, remitase a http://www.imap.org/.

El correo en Internet se basa fundamentalmente en textos ASCII puros y, en conjunto, no permite la utilizaci6n de datos que no sean ASCII. En principio, puede parecer restrictivo pero, despuks de considerar la amplia variedad de tipos de equipos entre 10s que se intercambian mensajes de e-mail, queda claro que, por razones pricticas, la elecci6n del minimo denominador comfin garantizaria la entrega segura de 10s datos. Sin embargo, la necesidad de adjuntar archivos distintos a ASCII a 10s mensajes de correo pronto se hizo evidente, por lo que se precisaba una norma para la codificaci6n de archivos binarios en ASCII de mod0 que pudieran ser transportados y, al recibirlos, poder decosdificarlos en su representation binaria nativa. Multipurpose Internet Mail Extension (MIME) define esta traducci6n y todas las reglas asociadas a la transmisi6n. Puede parecer mucho mis complicado de lo que es en realidad y, aunque su desarrollo puede resultar ligeramente pesado, no raz6n para preocuparse. El API JavaMail se encarga del trabajo tedioso y garantiza que todos 10s protocolos y traducciones necesarias se traten de forma correcta. Para mas informaci6n sobre MIME, visite http://www.oac.uci.edu/indiv/ehood/MIM4MlME.html.

El API de JavaMail es una colecci6n bastante amplia de clases e interfaces, que alcanzan un total aprcximado de 100. Esto hace que suene tremendamente complicado per0 no debemos dejarnos intimidar por la! cifras. De hecho, no es necesario preocuparse por comprender cada detalle para poder utilizar el API. Este es el poder de un sistema orientado a objetos: la capacidad de abstraer la implementaci6n y presentar una interfaz clara y concisa para la funcionalidad. En esta secci6n examinaremos 10s principales componentes que conforman el API JavaMail. Mis adelante, en este capitulo, profundizaremos en algunas las clases mis comfinmente utilizadas para comprobar la verdadera flexibilidad de este API.

JavaMail
Existen cuatro ireas principales:
0 Gesti6n de sesi6n

El aspect0 sesi6n del API define la interacci6n del cliente de correo con la red. Maneja todos 10s aspectos asociados con la comunicaci6n en su conjunto, incluido el protocolo que se utiliza para la transferencia y cualquier valor por defect0 que pueda ser requerido.
0 Manipulaci6n de mensajes Puesto que la premisa del API de JavaMail es enviar y recibir mensajes, no debe sorprendernos conocer la riqueza del API existente para la creaci6n y manipulaci6n de mensajes de correo.

O Almacenamiento y recuperaci6n de correo Si un rnensaje no se envia ni se recibe, se encuentra almacenado. Los mensajes son almacenados en jerarquias similares a las de archivos y directorios. El API de JavaMail dispone de un conjunto de clases para gestionar este almacenamiento, incluidas las que permiten afiadir, elirninar y trasladar rnensajes. O Transporte Finalmente, pero no menos importante, la entrega del mensaje. El API de JavaMail proporciona sencillos mecanisrnos para la entrega.

Instalacion y configuracion
JavaMail forma parte de la distribucion J2EE, aunque tambikn podemos utilizar ficilrnente el API de JavaMail como cualquier otra edicion; basta con descargar la 6ltima version del sitio: http://java.sun.com/products/javamail. En el momento de edici6n de este libro, la ultima entrega era JavaMail 1.2 (lanzado en Diciembre de 2000), que incluia implementaciones para SMTP, IMAP y POP3. La inchsi6n de la implernentacion POP3 se ha afiadido recientemente a la distribucion del API y completa la colecci6n de 10s protocolos mis utilizados para acceder a1 correo. Antes de utilizar el API de JavaMail, es necesario descargar e incluir el archivo JAR que compone el sistema de activaci6n JavaBeans, JavaBeans Activation Framework OAF). Se trata de un 6nico archivo JAR, a c t i v a t i o n . j a r , que hay que guardar en su ruta de clase. Se puede acceder a1JAF en el sitio de Sun a travks del siguiente enlace: http://java.sun.com/beans/glasgow/jaf.htrnl. Posterioremente, veremos la importancia de JAF para el API JavaMail. El A.PI de JavaMail integra una variedad de diferentes archivos JAR que nos permiten personalizar nuestra instalacion y distribucion. El archivo JAR m6s sencillo es m a i l . j a r ; contiene el API complete y las tres irnplementaciones de protocolo. La segunda configuraci6n no permite incluir solamente las implernentaciones que maneja nuestra aplicaci6n. C o n este fin, requerimos el archivo m a i l a p i . j a r . Los archivos i m a p . j a r , s m t p . j a r y p o p . j a r son completamente opcionales.

Compilaremos 10s ejemplos de este capitulo utilizando simplemente el archivo j2ee.jar de nuestra ruta de clase, lo que garantiza el uso de todos 10s protocolos.

iRapido, enviame un e-mail!


Antes de que realizar un recorrido exhaustivo por el API de JavaMail, analizaremos brevemente una de las tareas mis comunes asociadas al e-mail: el envio de un unico mensaje via SMTP. U n ejemplo de una situaci6n en la que podriamos emplear esta mtina seria proporcionar un formulario de comentarios en una pigina Web o informar sobre el estado de su aplicacibn. Sin mis rodeos, a continuaci6n examinaremos un fragment0 de codigo:

Capitulo 13
import import import import j avax.mai1. *; j ava:i. a c t i v a t i o n . *; javax.mai1. i n t e r n e t java.util.+;

.*;

p u b l i c c l a s s SendSMTP e x t e n d s O b j e c t { p u b l i c s t a t i c v o i d mairl(Strir1g a r g s [ ] ) { try {

//

C o n f i g u r a r 10s p a r h m e t r o s p r e d e t e r m i r ~ a d o s P r o p e r t i e s p r o p s = new P r o p e r t i e s ( ) ; props . p ~ l( t" m a i l . trar,sport . p r o t o c o l w , "smtp") ; prcpc . F J U ~ ( " . m a i l . s r r ~ t pt .v > s t " , " y o u r m a i l . y o u r s e r v e r . c a m 9 ' );

propc.put("mail.srntp.port",

"25");

//

C r e a r l a s e s i h n y c r e a r u r ~ rluevo m e n s a j e d e c r - , r r e o ( p r o p s ); Session rnailSession = Sessior~.getIrtstance b l e s s a g e rnsq = new MimeMessage ( m a i l s e s s i d r ~ ;)

//

C o r ~ f i g u r a r 1 0 s campos D E , PARA, FECHA y ASUNTO rnsy. s e t F r ~ : ~ r r ~ ( n e In wt e r n e t A d d r e s s ( " r n e @ m i n ec . ~ m 1" 1 ;

rnsg.setKecipients(Message.hecipier~tType.TO,
I n t e r n e t A d d l - e s s . p a r s e ( " i r ~ f o @ c o r r n acom") c. ) ; msg.setSentDate(new D a t e ( ) ) ; msg. s e t s u b j e c t ( " t h i s i s a s u b j e c t " ) ;

//

Crear e l cuerpo d e l c o r r e a r n s q . s e t T e x t ( " H e l l o f r o m my f i r s t

e-mail

with

JavaMail"); m e n s a j e .de c o r r e c

/ / P e d i r a l a c l a r e T r a n s p i ~ r t que T r a n s p o r t . s e n d ( r n s g );
]catch (Exception e ) { S y s t r m . o u t . p r i n t l r ~ ( e; )

enX/ie nuestro

Este programa, aunque no muy prictico ya que todos 10s valores estin refundidos, ilustra lo poco que necesitamos saber sobre protocolos subyacentes para enviar con exit0 un e-mail.

El programa asume que el servidor a trave's del cual intentamos entregar el mensaje tiene autoridad de reenvio para la direccidn I P de su clierzte o que la direccidn de e-mail desde la que enviamos el correo es va'lida para ese servidor. Por ello, no se asuste si n o recibe su correo; puede deberse a1 servidor S M T P de reenvio. Compruebe con el administrador del equipo si esta' o n o autorizado.
N o entraremos aqui en muchos mis detalles sobre 10s verdaderos pasos asociados al envio de mensajes, ya que examinaremos mucho mas de cerca el API de JavaMail en posteriores secciones. Por el momento, cabe destacar que, en este ejemplo, la mayoria del trabajo e s t i relacionado con la creacidn del mensaje de correo: la configuracidn de diversas propiedades como 10s campos DE,PARA y ASUNTO. El API de JavaMail ayuda a1 programador en cada paso del proceso. Hay clases para colaborar en la produccidn y validacidn de la mayoria de 10s aspectos asociados a la construccidn de este correo. Por ejemplo, posteriormente en este capitulo descubriremos utilidades que nos ayudarin a manejar las complejidades asociadas a1 trabajo con direcciones de e-mail de Internet.

JavaMail

Esta secci6n examinaremos algunas de las clases bisicas que componen el API de JavaMail. Analizaremos la funci6n global de la clase, asi como algunos de 10s mktodos rnis comunes que merecen especial menci6n. En la siguiente seccibn, pondremos todas estas clases en funcionamiento e ilustraremos algunos de sus aplicaciones mis comunes.

La clase j avax .mail.session define la sesi6n de correo utilizada para establecer la comunicacion con sistemas remotos de correo. Para 10s que estkn familiarizados con las sesiones de servlet, observeran que esta interpretation de sesiones no comparte ninguna funcionalidad comhn. Una sesi6n, en el context0 JavaMail, se utiliza simplemente para almacenar informaci6n sobre la logistics de establecemiento de sesiones de conexi6n con el servidor. Por esta raz6n, no es extrafio que 10s usuarios compartan sesiones si, por ejemplo, todas utilizan el mismo servidor SMTP. Observe que la clase session no maneja por si misma ninguna autorizacibn. Como veremos rnis adelante, ksta se realiza posteriormente. La clase Session puede, sin embargo, albergar informacibn de entrada. Por lo tanto, debe prestar especial atenci6n a la hora de tomar la decisi6n de compartir o no la clase Session con cualquier otra clase que se ejecute en ese momento en la JVM.
La clase session n o tiene constructores publicos con 10s que crear una nueva instancia. En su lugar, se obteniene mediante la invcocacion de uno de 10s mktodos estiticos de la clase. El primer metodo devuelve una instancia de session privada, no compartida con las Propiedades pasadas:
static Session getInstance(Properties prop)

Sin embargo, si deseamos tener una sesidn que otros usuarios puedan compartir dentro de la JVM, utilizariamos la siguiente llamada para obtener una nueva instancia:
static Session getDefaultInstance(Properties prop)

La diferencia entre las dos llamadas es que, cuando realizamos llamadas posteriores a1 ultimo metodo, kste devolveri la misma instancia devuelta en la primera llamada. Todos 10s parimetros de la clase Properties se ignoran. Si en cada ocasion necesitamos una nueva instancia, en su lugar se pueden utilizar cualquiera de 10s mktodos get Instance ( ) . Sin embargo, si fueramos a utilizar el mismo grupo de parimetros cada vez, por ejemplo proporcionando un primer plano a1 servidor de correo de su compaiiia, entonces seria rnis eficaz utilizar la misma session. El objeto session utiliza la clase j ava .util . Properties para poder pasar 10s distintos parimetros. Podemos obtener una instancia de esta clase creando una nueva y completando 10s parametros necesarios o utilizando la instancia devuelta por la llamada system. getpropert ies ( ) . El API de JavaMail define un conjunto de parimetros que 10s protocolos centrales utilizan. En la siguiente tabla, se muestra una breve descripcibn y 10s valores predeterminados de las propiedades de entorno JavaMail. Observari que la lista no especialmente exhaustiva; otras implementaciones de protocolo, por ejemplo Network News Transfer Protocol (que veremos rnis tarde) pueden requerir informacion adicional. Esta informaci6n (las configuraciones disponibles, etc.) debe ser provista por la documentaci6n del protocolo.

El objeto s e s s i o n es la clave para la experiencia de JavaMail. A travks de este objeto podemos acceder a1 resto de dreas principales del API.
Puede que algunos de 10s conceptos introducidos en la siguiente tabla n o le resulten familiares en este momento, per0 serin tratados con mucho rnis detenimiento a lo largo del capitulo.

Propiedad mail. transport. protocol mail.store. protocol mail. host

Descripcih Protocolo de transporte pedeterminado devuelto a1 i n v o c a r g e t ~ r a n s ~ o (r) t. Protocolo de almacenamiento predeterminado devuelto a1 lnvocar g e t s t o r e ( ) .. Host predeterminado que utilizarin Ibs protocolos de transporte y de almacenamiento, en caso de no especificar uno propio. Usuario pedeterminado que utilizaran 10s protocolos de transporte y de almacenamiento, en caso de n o especificar uno propio. Direcci6n de retorno del usuario actual. Invalida e l m a i l . h o s t del protocolo especificado. Invalida el m a i h s e r del protocolo especificado

Valor por defect0 Primer protocolo disponible de 10s que se han configurado. Primer protocolo dis onible de lor que re han con&urado Equipo local

mail .user

u s e r . name

m a i l . f rom mail.protoco1. host mail.protoco1. user

username@host mail .host

mail .user false

Volviendo a1 ejemplo de envio rdpido de e-mail SMTP, vemos que el proceso utilizado para obtener una variable Session va no tiene tanto misterio. Hemos creado una nueva instancia de P r o ~ e r t i e v s hemos asignado a las propiedades clave informaci6n que especifica que, a1 utilizar todos 10s mecanismos de transporte predeterminados, deseamos utilizar SMTP como agente de entrega:
P r o p e r t i e s p r o p s = new P l o p e r t i e s ( ) ; p r o p s . p u t ( " m a i l . t r a r ~ s p o r .tp r c , t o c o l " , " s r n t p " ) ; p r o p s . p u t ( " n l a i l . srntp. h o s t " , " y o u r m a i l . y ~ ~ u r s e r v eCCJIIL") r. props.put ("rnail.srntp.pbrtt', " 2 5 " ) ; Session mailSession Session.getInstance(props);

La s e s s i o n que hemos obtenido es privada, lo que significa que si modificarimos 10s parimetros para volver a obtener una variable s e s s i o n , la s e s s i o n devuelta no reflejaria las actualizaciones que acabamos de realizar a traves del metodo P r o p e r t i e s . p u t ( . . ) .

El objeto s e s s i o n nos permite acceder a las carpetas y dispositivos de almacenamiento de un sistema remoto gracias a1 uso de sencillas llamadas de metodo. Veremos su funcionamiento mis adelante, en este capitulo.

En la mayoria de 10s casos en 10s que se lee correo (o incluso enviindolo), es necesario proporcionar informaci6n para autentificar la conexi6n. Normalmente, 6sta adopta la forma de nombre de usuario y una contraseha con una descripci6n. El API de JavaMail previene esta eventualidad de un modo claro mediante la c l a s e ~ u t h e n t i c a t o rCuando . una sesi6n llega a1 punto en el que requiere 10s detalles de autentificaci6n necesarios, realiza una llamada a esta clase solicitando la informaci6n requerida. Para que esto suceda, hay dos variaciones en 10s metodos estiticos que hemos utilizado para obtener una s e s s i o n en la anterior secci6n.

static Session getInstance(Properties prop, Authenticator auth) static Session getDefaultInstance(Properties prop, Authenticator

auth)

Como puede ver, la linica diferencia esti en la referencia adicional a1 o b j e t o ~ u t h e n t i c aot r . Si pasamos e l v a l o r n u l l como referencia d e ~ u t h e n t i c a t o r estariamos , efectivamente realizando la misma llamada que hemos mostrado antes. Pero, ique sentido tiene pasar un valor n u l l ? Pasando un objeto n u l l para e l o b j e t o A u t h e n t i c a t o r indicamos que el objeto S e s s i o n no debe encargarse del proceso de autentificaci6n; nosotros lo haremos, en caso de que sea necesario. El disefio de un m6dulo de autentificacibn es relativamente sencillo, siempre que se implementen las interfaces necesarias y se sigan unas sencillas reglas. Cuando s e s s i o n necesite la contraseiia, realizari una llamada a1 metodo:

Este metodo procede de la clase a b s t r a c t a ~ u t h e n t i c a t o rLa . clase~assword~uthenticatio es nun simple envoltorio que permite que el nombre de usuario y la contraseiia se devuelvan a1 metodo que realiza la llamada. Analicemos un ejemplo sencillo para demostrar este proceso. Asumiremos que, cuando se solicite, se busca el usuario predeterminado en un archivo de texto de contraseiias. N o es la forma mis segura de manejar esta situacibn pero, para nuestros prop6sitos, ilustra lo esencial sin entrar en las complejidades de la conexion a una base de datos que, sin duda, seria una opci6n mucho mis acertada. Denominaremos a1 archivo de texto de nombres de usuario y contraseiias p a s s w d . s i l l y , a1 que aiiadiremos las siguientes lineas:
# #

passwd.silly El nornbre de usuario aparece a la izquierda y la contrasefia a la derecha

user o n e = s i l l y user two=password user three=12345

Para empezar, subclasificamos la clase A u t h e n t i c a t o r , proporcionando una implementaci6n para el metodoget~assword~uthenticatio (n ) ,como muestra el siguiente c6digo:
import j avax.rnai1. * ; import j ava. io. * ; import java.uti1.j; public class StupidAuthenticator Properties passwordList; extends Authenticator{

public StupidAuthenticator ( ) I super( ) ; try 1 / / Cargar el archivo clave de contrasefias = new Properties ( ) ; passwordList passwordList. load ( n e w FileInputStream("passwd. silly") ) ; ] catch(Exception e ) { System.out.println(e);

) { public PasswordAuthentication g e t P a s s w o r d A u t h e r ~ t i c a t i o r( ~ if ( p a s s w o r d L i s t . c o n t a i n s K e y ( g e t D e f a u l t U ~ e r N ( ) ) { return new PasswordAuthenticatior~ (getDefaultUserName (

Capitulo 13
(Strir~g)passwordList.get(getDefaultrJserName()) );
}

else I return

null;

I I
I A1 crear esta clase por primera vez, carga un archivo de texto de clave-datos de nombres de usuario y contrasefias utilizando el mecanismo j ava .utils . Properties.Tras ello, la clase queda inactiva hasta que un o b j e t o s e s s i o n la invocaa travks del mktodoget~asswordAuthentication( ) ,que posteriormente realiza una blisqueda en el objeto Properties y crea una nueva instancia de PasswordAuthenticat ion y la devuelve. En caso contrario devuelve el valor null. Para integrar esta clase en el procedimiento de autentificaci61-1de session,habria que modificar el c6digo original para incluir la clase StupidAuthenticator:
Properties props = new Properties(); props.put("mail.trar1sport.protoco1", " s m t p " ) ; props.put("mail.smtp.host", "yourmail.yourserver.corn"); p r o p s . p u t l"rnail.srntp.pc~rt", " 2 5 " ) ; StupidAuthenticator s A = new StupidAuthenticator ( ) ; S e s s i o n m a i l S e s s i i ~ n = Session.getIr,stance(props, s A ) ;

C o n este codigo, el objeto StupidAuthenticationr se encarga de recopilar las


contraseiias.

Una de las caracteristicas esenciales de JavaMail es la capacidad de trabajar con mensajes. Como hemos visto, el verdadero procedimiento para enviar un e-mail no es tan complicado. Sin embargo, el proceso que provoca mayor confusion es la generacion del mensaje que se va a enviar. Adaptarse a todas las norrnas MIME para garantizar una transrnisi6n segura y coherente puede resultar bastante complicado. N o se preocupe. JavaMail acude en su ayuda. El API dispone de una completa biblioteca de clases para que la construcci6n y deconstruccion de mensajes de correo resulte relativarnente sencillo, todo ello por medio de j avax .mail .Message. Esta clase abstracta proporciona el contenedor bisico para la representation de un mensaje de correo, tal y como ilustra de forma esquemitica el siguiente diagrama:

U n mensaje de correo esti formado por dos componentes principales: la cabecera y el contenido. La cabecera contiene toda la i n f o r m a c i h que describe las caracteristicas del mensaje, por ejemplo, el campo del asunto, 10s receptores del mensaje, el rernitente del mensaje, la fecha en que ha sido enviado, etc. Todos estos campos, as6 como algunos otros, forman parte de la cabecera. Los datos propios del mensaje se encuentran en la secci6n de contenido. La clase Message define esta composicion implementando la interfaz j avax .mail. Part, que trata la funcionalidad asociada a la construcci6n del contenido.

JavaMail
Aqui es donde se complica el API de JavaMail, a la hora de tratar 10s contenidos del mensaje. Esto se debe a que la especificaci6n MIME permite multiples partes, cada una con su propia codificaci6n y atributos, que se enviarin en el mensaje. Esto es lo que otorga poder a MIME y, en ocasiones, lo que dificulta su manejo. Examinaremos este conjunto de clases e interfaces para, quizis, aclarar un poco esta marafia de clases interconectadas.
Aunque utilizaremos el formato de mensaje mds comtin, M I M E , el A P I de JavaMail ha sido disefiado para utilizar cualquier tip0 de mensaje, permitiendo la presencia de otras implementaciones. Para 10s objetivos de este capitulo, nos centraremos en la norma que tna's se emplea en u n entorno de Internet.

La claseMessage es una clase abstracta y por lo tanto, para utilizar un mensaje de correo, debemos aplicar una implementation subclasificada. La implementaci6n que forma parte del API de JavaMail es j a v a x . m a i l . i n t e r n e t .MimeMessage. Existen diversas tecnicas para obtener una nueva instancia de esta clase. El primer metodo consiste en invocar realmente uno de sus constructores publicos:
public public MimeMessage (Session session) MimeMessage(MimeMessage msg)

El primer metodo crea unMimeMessage vacio basado en las propiedades de S e s s i o n pasadas. N o es el mod0 rnis comun. Una alternativa es utilizar el constructor de copias, que crea una nueva instancia de mensaje con las mismas propiedades y contenido de la que se ha pasado. Puede resultar un mod0 de crear un nuevoMimeMessage poco eficiente y debe evitarse siempre que sea posible. Una de las situaciones en las que podemos pensar en utilizar este derivado es a la hora de crear un mensaje como respuesta a e-mail ya existente. Afortunadamente, 10s creadores del API de JavaMail fueron un paso rnis alli en este aspect0 y consiguieron el siguiente metodo:
public Message reply (boolean replyToAl1)

se puede emplear para crear de forma sencilla un nuevo mensaje con todos las cabeceras necesarias configuradas, incluida la modificaci6n del asunto para incluir el prefijo "RE : ",en caso de que a6n no estuviera configurado. Puesto que esta clase se utiliza para trabajar con mensajes de correo de Internet, examinaremos rapidamente algunos de 10s mktodos disponibles para acceder a 10s campos de cabecera comunes que existen como parte de la especificaci6n del mensaje (tal y como se detallan en RFC#822; vease http:// Es una cabecera extraida directamente de un mensaje recibido del ~~w.rfc-editor.org/rfc/rfc822.t~t). popular servicio hotmail.com (observe que algunos campos han sido eliminados para mayor claridad):
Me.qsagr-ID: ~OOle01c0feab$0366b7e0$8~74f5dl@comp~1tir> Fr8?m: V o r m a c W i l l i a m s o n " < c o r m a c w i l l i a m s o r r C a h o t m a i l c o m i T a : a l a n @ n - a r y .com S u b j e c t : Re: ttlartlrs -0400 D a t e : Tue, 2 6 J u n 2 0 0 1 2 1 : 4 6 : 3 9 MIME-Vsrsi~rt: 1.0 C~ntent-Type: text/plain; charset=us-ascii 3 - E r r : 1-MSMail-Prit,rity: Normal "-Mailer: Microsoft Outlook Express 5.00.2615.200

Examinernos un poco rnis de cerca algunos de 10s campos rnis comunes que podrian encontrarse en una tipica cabecera.

El mensaje de correo debe provenir de, a1 menos, una persona, que apareceri detallada en la cabecera De del mensaje de correo. Este campo debe ser una direcci6n de correo de Internet de formato vilido y la clase Message proporciona un grupo de mktodos para configurar y recuperar estos datos. Para leer el campo, utilice el mktodo:

Este m i t o d o devolveri una matriz de objetos j avax .mail.Addressque representan las direcciones de e-mail. N o se preocupe demasiado por la composici6n de esta clase en estos momentos; mis adelante analizaremos su funcionalidad con mayor detenimiento. Por el momento, considerela una clase envoltorio para representar una direcci6n vilida de Internet. Por el contrario, la configuraci6n del campo puede conseguirse mediante unos sencillos metodos de acceso:
void setFrom() void setFrom(javax.mail.Address fromAddress)

Quizis la primera versidn le confunda un poco. i C 6 m o configuramos el campo De sin pasarle realmente nada? Si recuerda el anilisis de session,hemos analizado las diferentes propiedades por defect0 que podiamos asociar a una determinada sesion de correo. Este metodo simplemente utiliza la propiedad predeterminada de la sesidn para el campo De para el mensaje. El segundo metodo sencillamente nos permite especificar una direcci6n alternativa para ser utilizada en el campo De. Ademis, si deseiramos configurar multiples direcciones para el campo De,podemos utilizar el mktodo:
void addFrom(Address[l moreAddresses)

Esto afiadiri la matriz de direcciones a1 campo De existente.

Para, CC y CCO
Existen tres amplias clasificaciones para dirigir mensajes de correo: Para,cc y CCO. El campo Para esti normalmente destinado a 10s receptores a 10s que el mensaje va directamente dirigido. El campo cc representa "Copia de Carb6nM (por razones hist6ricas) y esti destinado a receptores que estin recibiendo una copia del mensaje, donde son publicamente reconocidos. El campo cco (en ingles, BCC) representa "Copia de Carb6n Oculta" y esti destinada a receptores que reciben una copia del mensaje que 10s otros receptores n o ven. Fundamentalmente, las tres categorias operan exactamente del mismo mod0 y, con esa finalidad, la clase Message facilita la configuracidn y recuperaci6n de las diversas cabeceras:
void setRecipient(Message.RecipientType type, Address[] addresses) void setRecipient(Message.RecipientType type, Address address) Address [ I getRecipients (Message.RecipientType type) Address[] getAllRecipients()

Ademis de 10s mktodos setRecipient ( . . . ) ,existen derivados del metodoadd~eci~ient ( . . .) para adjuntar ficilmente nuevas direcciones a campos de direcciones ya existentes. Message .RecipientType define las siguientes constantes:

JavaMail
Adernis,MimeMesage define un tipo adicional que se puede utilizar con protocolos que sirven grupos de noticias a travts del protocolo Network News Transfer Protocol (TNP):

Utilizando estos mttodos, podernos configwar 10s diversos carnpos, corno rnuestra el siguiente fragrnento de codigo:
S e s s i o r ~ r n a i l S e s s i o n = Sessior~.getInstance(props); M e s s a g e ms.3 = new MimeMessage ( r n a i l S e s s i o r i ) ; rnsg.setRecipier~ts (Mecsage.Recipier~tType.TO, InternetAddress .parse ( " i r ~ f o @ c o r n " )) ; rnsg. s e t R e c i p i e n t s ( M e s s a q e . R e c i p i e r ~ T t ype. CC, I r ~ t e r n e t A d d r e s sp . a r s e ( " i r ~ f o @ w r ocorn" x. ) ) ; msg.setRecipients (Message.Recipier~tTjipe.BCC, Ir~ternetAddress . p a r s e ( " s e c r e t @ w r o x com") . ) ;

Responder a
Hay situaciones en las que quizis deseernos que un rnensaje de correo proceda de una persona determinada, per0 querernos que la respuesta vaya a otra distinta. Por ejernplo, digarnos que el presidente de su cornpafiia anuncia un product0 irnportante; el podria crear el e-mail, per0 si alguien contesta pidiendo mis inforrnaci6n, puede que decida que se responsabilice de la respuesta el equipo de ventas. El correo estindar permite esta opci6n gracias a1 carnpo especial R e s p o n d e r A. El API proporciona dos mttodos para trabajar con este carnpo de cabecera. Para configurar el carnpo, utilice el rnttodo:
void setReplyTo (Address [ I addresses)

Si no invocarnos este rnttodo, se supone que seri n u l o y la cabecera Responder A no seri incluida en la cabecera del mensaje resultante. Para recuperar la cabecera Responder A, sirnplemente invoque:
Address [ 1 g e t ~ e p l y T o 0

Si no estuviera presente esta cabecera, este rnttodo devolveria la rnisrna inforrnacidn que si estuvitrarnos invocando g e t F r om ( ) .

Asunto
Corno podriarnos esperar, existen rnttodos para configurar la cabecera A s u n t o de un rnensaje de correo:
void setsubject (String subject) String getsubject ( )

Fecha
Accedernos a1 carnpo F e c h a del mensaje de correo utilizando 10s siguientes rnttodos:
void setSentDate (Date date) Date getSentDate ( )

ID del mensaje
Cada e-mail que se envia por Internet debe disponer de un identificador exclusivo. Por ello, en teoria, si todos 10s e-rnail consiguen llegar a un gran alrnacen de datos, podrernos indexarlos. El API de JavaMail genera el id. del rnensaje cuando lo pardarnos. Podernos leer el campo de ID-Mensa j e en 10s mensajes:
String getMessageID ( )

Capitulo 13
Otros... La cabecera de mensaje fue diseiiada para ser lo suficientemente flexible como para permitir la aparici6n de cualquier numero de cabeceras. Podemos utilizar esta funci6n para comunicar datos adicionales entre mensajes de correo. Por ejemplo, Microsoft utiliza esta funci6n con frecuencia cuando 10s mensajes son transferidos entre clientes de correo Microsoft. Cuando dos clientes Outlook intercambian datos, por ejemplo, la aplicaci6n aiiade informaci6n adicional en la cabecera para permitir sencillas funciones como la devolucidn de receptores o la planificaci6n de la information. Para afiadir un nuevo uso de cabecera:
void setHeader(Strin9 name, String value)

Y, a la inversa, para leer una cabecera especifica podemos utilizar:


String getHeader(String name, String delimiter)

El delimitador por defect0 utilizado en cabeceras de e-mail es la coma ( , ) per0 esta no es una norma irrevocable y podemos en realidad especificar nuestro propio delimitador. Ademis de estos metodos, existe toda una gama de mktodos que nos permiten tener un mayor acceso a la informaci6n de cabecera del mensaje.

El API de JavaMail ofrece una rica interfaz para reunir un grupo bastante complejo de partes de mensaje, que se controla en su totalidad mediante el uso de la interfaz j a v a x . m a i l . P a r t y sus derivados. Es justo comentar que muchos programadores se preguntan ansiosamente c6mo encajarin todas las relaciones. Teniendo esto en mente, demos un paso atris por un momento y examinemos la estructura en su conjunto. Podemos pensar en la construcci6n de mensajes de correo como si ocurriera en bloques 16gicos o partes, donde cada bloque es en realidad una unidad de datos. Por ejemplo, un archivo adjunto seria considerado un bloque, a1 igual que el cuerpo textual principal para el mensaje, que seria otro bloque. Ahora, considere el hecho de que, en su forma inicial, un rnensaje s61o puede tener un bloque de datos. i C 6 m o podemos adjuntar mdtiples bloques de datos a un Gnico mensaje? Este problema es el que soluciona la norma MIME con su variedad de tipos MIME. Pero, por el momento, q u e d h o n o s con el mundo de JavaMail antes de examinar implementaciones especificas. U n mensaje puede contener un unico bloque o bien un bloque especial que, en si mismo, puede albergar una lista de bloques. Ademis, un bloque puede albergar un Gnico bloque o un bloque especial para indicar una lista. Y asi sucesivamente. En JavaMail, un mensaje puede albergar una Gnica pieza de datos o un j a v a x . m a i l . M u l t i p a r t como contenido. La c l a s e ~ u lit p a r t es un espacio destinado a la existencia de mdtiples partes. Sin embargo, existe una relaci6n especial con una P a r t e que esti contenida en el c o n t e n i d o ~ utl i p a r t , en lugar de formar parte del contenido central del mensaje de nivel superior. Una clase especial llamada j a v a x . m a i l . B o d y P a r t es utilizada en una listade c o n t e n i d o ~ u l t i p a rpara t denotar 10s bloques de datos que forman el bloque completo de contenido. Asi, una c l a s e ~ u l t i p a rs61o t puede albergar clases B o d y P a r t y una clase B o d y P a r t , en si misma muy similar a la c l a s e ~ e s s a g epuede , albergar un Gnico bloque de contenido o una unica c l a s e ~ u l t i ~ a r t . Esto queda demostrado en el siguiente diagrama, que ilustra la composicidn de contenido de un mensaje tipico:

JavaMail

-+ Contlene

Conten~do

JavaMail proporciona una implementation de esta estructura utilizando MIME. La implementation MIME sigue el modelo y las clases reales utilizan 10s mismos nombres que sus hom6logas abstractas, except0 la palabra Mime situada delante de cada uno de ellos. Antes de profundizar en las clases, veremos c6mo se almacena el contenido. Para ello, necesitamos examinar brevemente el Sistema de Activacion de JavaBeans.

Sistema de activation de JavaBeans


Si en el mundo solo hubiera tipos de datos centrales de Java, entonces seria mucho rnis ficil trabajar en kl. Obviamente, kste n o es el caso. La norma MIME, sin embargo, permite el envio de una amplia gama de tipos de datos como contenido en cualquier parte siempre que estC correctamente etiquetado utilizando la convencion "xxx/yyy". Por ejemplo, ya hemos visto como minimo un tip0 de datos MIME, t e x t / plain, que resulta ficil de manejar con un objeto j ava lang String.

~ s t es a probablemente la forma rnis sencilla de contenido y, por lo tanto, n o es realmente representativa. Para enfrentarse a esto, el API de JavaMail emplea 10s servicios del Sistema de Activacidn de JavaBeans, JavaBean Activation Framework (JAF), para ofrecer una interfaz limpia y consistente a la amplia gama de tipos de datos que puedan existir.

Puede encontrar ma's detalles sobre JAF visitando la direccidn del sitio W e b de Sun:
http:lljava.sun.comlbeans/glasgow/ja~html.
El sistema JAF proporciona la clase j avax . activation. DataHandler para manejar las operaciones necesarias que pueden ser ejecutadas en 10s datos. Cuando la clase Part esti manejando contenido, todas las operaciones son ejecutadas a travks de la clase DataHandler, aunque la clase Part no expone algunos mktodos abreviados, que veremos rnis tarde. Para ofrecer una idea de la funcionalidad disponible enDataHandler,la siguiente tabla muestra algunos de 10s mCtodos rnis comunes:

String getContentType ( ) Object getcontent ( )

Devuelve el tipo MIME del objeto, incluido cualquier parimetro asociado a 61. Devuelve 10s datos. Si e l ~ a t a ~ a n d l e ha r sido creado c o n u n objeto, entonces este mktodo lo devuelve. Silos datos han sido creados utilizando Datasource,entonces Csteintentariencontrarelcontenido~b j ect y devolverlo. D e no ser asi, se devuelve InputStream. Devuelve un flujo de entrada a1 objeto que esti albergandol representando 10s datos.

Inputstream getInputStream()

Capitulo 13

Outputstream getoutputstream() void writeTo outputstream outputs)

Devuelve un flujo de salida a1 objeto que esti albergando/ representando 10s datos por lo que el contenido puede ser sobrescrito. Es un metodo de conveniencia que escribiri el contenido de datos en el flujo de salidapasado.

El API de JavaMail proporciona D a t a H a n d l e r s por defect0 para 10s tipos MIME rnis cornunes:
0 0 0

t e x t / p l a i n . Para rnensajes que son sirnplernente texto ASCII t e x t / h t m l . Para rnensajes que son construidos utilizando texto HTML m u l t i p a r t / m i x e d . Para rnensajes que estin cornpuestos de diferentes tipos, por e j e m ~ l oque , contienen un docurnento adjunto

0 m e s s a g e / r f c 8 2 2. Define la norrna de Internet para rnensajes de texto.

Aunque quizis n o se haya dado cuenta, en nuestro ejernplo sencillo de corno enviar un e-mail, la clase M i m e P a r t manejaba en realidad el D a t a H a n d l e r por nosotros. iRecuerda c6rno configurarnos el contenido para el correo de texto?
msg. setText ( " H e l l o f roni my
first

e-mail with

JavaMail") ;

La clase MimeMes s a g e ha provisto algunos mitodos de conveniencia que nos perrniten establecer ripidarnente 10s datos para sencillos tipos de contenido. Podriarnos haber conseguido a1 rnismo efecto invocando todos 10s cornponentes nosotros rnismos:
messaqeBody = "Hello f l - o m my first e-mail with JavaMail"; DataHandler d h = riew DataHar~dler(messageBody, " t e x t / p l a i n W ) ; msg.setDataHandler(dh);
Stririg

En este ejemplo, hernos creado una nueva instancia de una clase s t r i n g y la hernos configurado con el texto del cuerpo de nuestro rnensaje. A continuaci6n, hemos creado una nueva instancia D a t a H a n d l e r , pasando un objeto s t r i n g y etiquetando estos datos con el tip0 t e x t / p l a i n . Finalmente, configurarnos el contenido del rnensaje en esta nueva instancia. Observe que estos cornponentes estin envueltos en una finica llarnada aMimeMessage s e t T e x t ( . . ) .

A1 llegar rnitodos - a la inforrnacibn, utiliza la clase D a t a K a n d l e r y la interfaz p a r t define algunos abreviados por nosotros, por ejernplo el rnitodo P a r t . g e t c o n t e n t ( ) invocado en una parte de tip0 t e x t / p l a i n devolveria un objeto S t r i n g . Pero, para 10s prop6sitos de nuestra ilustraci6n y para reforzar la noci6n de que una clase especifica D a t a H a n d l e r rnaneja el contenido del rnensaje, harernos el recorrido largo:

Prirnero recuperarnos una instancia de D a t a H a n d l e r que alberga 10s datos para nosotros. Despuis cornprobarnos el tip0 de contenido de 10s datos. Esto nos perrnite deterrninar c6rno utilizar el objeto devuelto por la invocaci6n d e ~ a t a ~ a n d l . egre t c o n t e n t ( ) . Recuerde: hernos creado esta instancia de D a t a H a n d l e r pasando una referencia S t r i n g a su constructor, por lo tanto, como indica la docurnentaci6n del API JAF, una llarnada a g e t c o n t e n t ( ) devolveri el objeto original que hernos utilizado para crear el contenido, que en este caso en la referencia s t r i n g . Asi que reenviarnos la r e f e r e n c i a ~ be j c t devuelta p o r g e t c o n t e n t ( ) a1 o b j e t o s t r i n g .

Veremos mis adelante en este capitulo como utilizar la funci6n g e t I n p u t S t r e a m ( ) de la clase D a t a H a n d l e r para manejar tipos de datos que n o tienen una implementacibn D a t a H a n d l e r , por ejemplo el tipo MIME i m a g e / j p e g , utilizado para representar imigenes.

C o m o ya hemos analizado en la secci6n anterior, una multiparte es disefiada para gestionar multiples partes como si fueran una sola unidad. La situaci6n mis comun en la que podriamos encontrarla es el momento de adjuntar un archivo a un e-mail. El cuerpo del mensaje seria una parte y el archivo adjunto seria otra. Por lo tanto, tendriamos que utilizar un mensaje MIME multiparte para empaquetarlo todo para una transmisi6n efectiva. Analice por un momento el siguiente fragmento de c6digo que ilustra la construccion de las dos partes del mensaje de correo:
MirneMessage rnsg = new M i n i e M e s s a g e ( s e s s i o n ) ; Multipart n i a l l B o d y = r ~ e w M i n i e M u l t l p a r t ( ) ;

/ / Crear l a primera p a r t e M i m e B o d y P a r t r n a i n B o d y = new M i m e B o d y P a r t ( ) ; mair~Body.setTe:<t("Here i s t h e f i l e I p r o m i s e d rnailBody. a d d B a d y P a r t (mair1Body) ;


//

you.");

C r e a r l a segurlda p a r t e c o n a 1 arlexo F i 1 e D a t a S o u r c e f d s = new F i l e L l a t a S o u r c e ( " c :\ \ t e m p \ \ p h o t o . j p g " ) ; M i r n e B o d y P a r t m i m e A t t a c h = new M i m e B o d y P a r t ( ) ; rnirneAttach.setDataHarjd1erjrtew D a t a H a n d l e r ( f d s ) ) ; r n i r n e A t t a c h . s e t F i l e t J a n l e ( f d s .getNarne ( ) ) ;

C o m o puede ver, en primer lugar creamos una nueva instancia d e ~ i m e ~ u ip la t r t , la implementacidn para la clase abstracta M u l t i p a r t . ~ s t serviri a como espacio reservado que nos permitiri insertar tantas partes como nos sea requerido. En este ejemplo, s610 necesitamos dos: una para el texto del mensaje y otra para el archivo. Despuks creamos una instancia d e ~ i m e ~ o d y ~que a r albergari t el contenido para el texto de nuestro mensaje y, como puede verse, como sabemos que el texto del mensaje es de tip0 t e x t / p l a i n , estamos utilizando un metodo abreviado s e t T e x t ( . . . ) para configurar el texto. A continuaci6n, tomamos la ) pasando instancia y la adjuntamos a M i m e M u l t i p a r t realizando una llamada a a d d B o d y P a r t ( nuestra r e f e r e n c i a ~ i m e ~ o d ~ ~ a r t .

...

Kepetimos esta operacion para el archivo adjunto, finalizando con una llamada a1 metodo a d d B o d y P a r t ( . . .) . Finalmente, una vez hayamos terminado de crear todas las partes necesarias que componen el mensaje multiparte, configuramos el contenido de nuestroMimeMessage original en MimeMult i p a r t . N o se preocupe demasiado por la logistica de adjuntar un mensaje; la analizaremos con detenimiento en el ejemplo que trata directamente 10s anexos, mis adelante en este capitulo. Internamente, M u l t i p a r t almacena ]as diversas partes en un j a v a u t il . v e c t o r y, con ese fin, la mayoria de 10s mktodos p6blicos de esta clase son meramente envoltorios, que nos permiten gestionar la lista de B o d y P a r t s . Los mktodos m i s comunes d e ~ u l t i ~ aaparecen r t en la siguiente tabla:

Void addBodyPart BodyPart bp)

Afiade B o d y P a r t b p a1 final de la h a actual d e ~ o d y ~ a r t s .

Capitulo 13

Void addBodyPart BodyPart bp, i n t i n d e x) BodyPartgetBodyPart i n t index) S t r i n g getContentType() i n t getcount ( ) Part getparent () b o o l e a n removeBodyPart BodyPart bp) b o o l e a n removeBodyPart ( i n t index)

Aiiade B o d y P a r t b p a la lista en el indice especificado. Devuelve e l ~ o Pd ar ~t que se encuentra en laposici6n pasada. Devuelve el tipo MIME para e s t a M u l t i p a r t . Devuelve el ntimero de B o d y P a r t s de la h a . Devuelve la parte principal que alberga en ese momento esta M u l t i p a r t . Devuelve n u l l si todavia no esti asociado. E l i m i n a l a i n s t a n c i a ~ o d y ~ ab r tp de l a h a . Devuelvet r u e si la encuentra o f a l s e si no la encuentra.
Eliminalainstancia~ody~artde lalistaenlaposici6nespecificada. Devuelve t r u e si la encuentra o f a l s e si no la encuentra.

v o i d s e t p a r e n t ( P a r t p a r e n t ) Asocia la parte principal d e ~ u li t partget. Como puede ver, no existe mucha complejidad asociada a la c l a s e ~ u l t i ~ a Su rt. principal proposito es sencillamente gestionar la lista de B o d y P a r t s que se le ha pedido que albergue. Hablando d e ~ o d y ~ a r t s , examinemos mis de cerca las propiedades asociadas a albergar datos.

Continuando la secci6n anterior, B o d y P a r t es la clase abstracta utilizada para denotar la parte que conforma u n a M u l t i p a r t e . La clase B o d y P a r t es idCntica a la clase P a r t except0 en que tiene un metodo adicional aiiadido para obtener l a ~ u l i t p a r t en e la que esti incluida esta parte:
Multipart g e t p a r e n t 0

D e nuevo, esto no es muy complicado.

Contenido del mensaje


El mensaje tiene una variedad de metodos que nos permiten determinar cdmo manejar el contenido del mensaje y la composicidn de datos. Como ya hernos descubierto, un mensaje puede ser compuesto utilizando una serie de diferentes partes y, con esta finalidad, todos 10s mktodos descritos en esta secci6n se encuentran en la interfaz P a r t en oposicion a la clase a b s t r a c t a ~ e s s a ~ e . La especificaci6n MIME establece que todas las descripciones de tipo de contenido estCn en formato xxx/ yyy, donde xxx es el tip0 principal y yyy es el sub-tipo. Cada P a r t e tiene su propio formato MIME y, para determinar el formato, podemos utilizar el metodo:
String getContentType 0

Este metodo puede devolver, por ejemplo, el tipo " t e x t / p l a i n ; c h a r s e t = u s - a s c i i " corno hemos visto antes en el mensaje de correo de Internet. Quizis piense que esto no es vilido puesto que parece tener inforrnacion adicional despues del formato xxx/yyy, pero son datos de parametros. La norma MIME perrnite que la information adicional sea transferida en este atributo que ayudari en la fase de decodificacion y codificacidn del mensaje. Puesto que hemos tomado muchas decisiones basadas hicarnente en el forrnato xxx/yyy, tenemos un metodo de ayuda que nos asiste a la hora de determinar si un tip0 concreto MIME esti o no presente. El metodo:
boolean isMimeType (String mimeType)

JavaMail
nos facilita determinar un tip0 concreto. Podemos pasar " t e x t / p l a i n w para comprobar si el contenido es de ese tipo. Podemos incluso pasar " t e x t / * " para ver si el tipo MIME es como minimo de tipo " t e x t / " . Esto resulta particularmente 6til a la hora de determinar si el contenido es o no m u l t i p a r t / *. Por ejemplo:
if
(rnsg. isMirrleTy~e ("muitipart/*") { Systern.r,ut . p r i r ~ t l n ( " T h i s message has multiple parts") ;

I
Ademis, la especificaci6n MIME permite una mayor descripci6n a travks de 10s atributos opcionales descripci6n, disposici6n y nombre de archivo. Hay aspectos especificos sobre cbmo deberia ser empaquetada esta informaci6n pero, como estamos trabajando a travks del API de JavaMail, no necesitamos realmente preocuparnos por el formato subyacente; resultad mis ficil gracias a las llamadas de mitodo. Examinemos mis detenidamente estos atributos opcionales. El campo de descripci6n nos permite establecer algunas notas descriptivas sobre esta parte MIME concreta. Naturalmente, existen mitodos que realizan esta operaci6n:
String getDescription ( ) void setDescription (String desc)

El campo de disposici6n es particularmente litil, en especial en la situacidn en la que se estin utilizando e-mail de formato HTML. Describe si una parte debe ser guardada como documento adjunto o utilizada internamente para mostrar el mensaje. El API de JavaMail define dos constantes s t r i n g para este estado:
static public static public String ATTACHMENT String INLINE

Utilizindolo, podemos configurar o comprobar la disposici6n de la parte invocando 10s mitodos apropiados:
String getDisposition ( ) void setDisposition(String disp)

Entonces, por ejemplo, si quisikramos comprobar si una determinada parte que contiene un anexo, debe ser utilizada internamente o guardada en el disco, podriamos utilizar la siguiente Ilamada:
String dispos i f ( d i s p o s == msq.getDisposition( 1 ; n u l l I I d i s p o s e q u a l s I g n o r e C a s e ( P a r t .ATTACHMENT) ) { Systern.out.printlrt("This p a r t s h o u l d b e t r e a t e d a s a n a t t a c n r n e r t t " ) ;
=

Por d t i m o , la especificacion MIME establece que si es un archivo adjunto, entonces podemos ofrecer un posible nombre que se utilizari cuando guardemos el anexo. El nombre de archivo pasado no contendri ninguna informaci6n de directorio y consistiri sencillamente en el nombre del archivo, incluyendo cualquier extensi6n que pudiera tener el archivo. Los mitodos para operar con este campo son:
String getFileName 0 void setFileName (String fname)

Ademis de estos parimetros, podemos determinar el tamaiio del mensaje y el recuento de lineas invocando 10s siguientes mitodos:
int getsize() int getlinecount 0

Esta informaci6n es particularmente 6til para clientes ya que les permite determinar si deberian o n o preocuparse por descargar el mensaje en una conexi6n lenta, por ejemplo en un dispositivo inalimbrico. Sin embargo, fijese en que n o siempre es posible recuperar las dimensiones de un mensaje de correo. Si 10s

Capitulo 13
valores no pueden ser determinados, entonces se devuelve - 1. Si esto no es suficiente para desanimarle en el uso de estos mitodos, considere tambien el hecho de que, debido a 10s algoritmos de codificaci6n del mensaje, 10s valores devueltos quizis no sean un verdadero reflejo del tamafio real y el recuento de lineas exacto de una parte concreta del mensaje.

lndicadores de mensaje
C o m o ya hemos visto, un mensaje tiene una amplia gama de atributos asociados para describir sus contenidos y propiedades de direccionamiento. Sin embargo, ninguno de 10s atributos que hemos examinado hasta el momento llega tan lejos como para otorgar a1 mensaje un "estado". Por ejernplo, en la actualidad, no tenemos ninguna forma posible de saber si un mensaje es nuevo o si es una respuesta a un mensaje existente o incluso si ha sido leido o respondido. El API de JavaMail ayuda a1 desarrollador proporcionindole un mecanisrno para almacenar ficilmente este tip0 de informacion en cada mensaje.

Debemos destacar en este punto que no se debe confiar en estos indicadores de estado. Su implementacidn y la posibilidad de determinar el estado de un mensaje recaen en el proveedor individual. Aqui, el proveedor es responsable de la implementaci6n del protocolo subyacente. Por ejemplo, determinar el estado de SEEN puede no serposible en una implementacidn de grupo de noticias ( N N T P ) , puesto que el protocolo N N T P no tiene un estado que represente si un puesto de grupo de noticias ha sido leido, ya que el registro de esta parte queda en el programa cliente.
Ademis de 10s indicadores estindar, el API de JavaMail permite la adici6n y manipulation de indicadores de estado definidos por el usuario. La gesti6n de indicadores se realiza utilizando la clase envoltorio j avax .mail. Flags. Esta clase gestiona todos 10s indicadores de estado incluidos 10s estados de sistema y 10s definidos por el usuario. Los indicadores centrales del sistema ofrecen una amplia gama de caracteristicas que son las siguientes:

O Flags.Flag.ANSWERED Si el mensaje ha sido respondido por otro e-mail, entonces se establece este indicador.
O

Flags.Flag.DELETED Si el mensaje ha sido indicado para ser eliminado, se establece este indicador. Como veremos mis adelante en este capitulo, despuCs de una llamada para borrar la carpeta, todos 10s mensajes con este indicador serin eliminados. Flags.Flag.DRAFT Si el mensaje no ha sido enviado, se establece este indicador. Flags. Flag. FLAGGED Si el mensaje ha sido enviado, el cliente ha marcado el mensaje por algun motivo.

0 0

D Flags. Flag. RECENT

Si aparece este indicador, el mensaje ha sido enviado desde la Gltima vez que el cliente abri6 la carpeta.
O

Flags.Flag.SEEN Si el indicador ha sido leido, se establece este indicador. El cliente puede cambiar el estado de este indicador si asi lo desea. Flags. Flag.USER Este indicador determina si la carpeta puede o no ajustarse a indicadores definidos por el usuario. Observe que Cste no es el verdadero indicador definido por el usuario; es meramente una indicaci6n de la posible existencia de tales indicadores.

La compatibilidad con estos indicadores depende completamente del proveedor. Por ejemplo, el protocolo P O P s61o es compatible con el indicador Flags. Flag. DELETED. N o se adapta a ninguno de 10s otros.

JavaMail
En principio, esto puede parecer insuficiente. Por fortuna, no es tan malo como parece y podemos determinar quC indicadores son compatibles invocando el metodo:
public Flags getPermanentFlags()

Este metodo es invocado desde la clase j avax .mail .Folder (que analizaremos mis adelante, en este mismo capitulo). Los indicadores son utilizados para registrar 10s estados de 10s mensajes y para permitirnos realizar operaciones s61o en ciertos mensajes que satisfagan un estado particular. Por ejemplo, como descubriremos mis tarde, podemos ficilmente enumerar 10s mensajes de una carpeta que tiene configurado el indicador SEEN. La clase j avax .m a i 1 .Mess age tiene un grupo de metodos que nos permite cornprobar y establecer el estado de 10s indicadores. Por ejemplo, para comprobar si un mensaje ha sido o no leido, podriamos utilizar:
if (rr~sg.isSet ( F 1 a g s . F l a q . S E E N )) System.out . p r i n t l r i ( " T h i s message has beer, r e a i " 1 ;

Los indicadores de mensaje son una genial adici6n a1 registro de mensajes per0 debe tener cuidado a1 utilizarlos: no puede confiar en ellos en todas las implementaciones del protocolo subyacente y seri necesario que comprobemos si el servidor es compatible con ellos. Los principales metodos de manejo de indicadores de j a v a x .m a i 1 .Mess age se resumen en la siguiente tabla:

Mitodo
boolean isExpunged ( )

Descripcion Comprueba si el mensaje ha sido borrado despues de ser marcado para su elirninacion. Paraclarificar este termino, en este context0 "expunged" indica si el mensaje ha sido eliminado de la carpeta. Este metodo comprueba el estado del indicador especificado. Devuelve una copia del objeto Flags. Observe que si hubiera que modificar cualqu~erade 10s indicadores de este objeto, no tendrianingh efecto sobre 10s indicadores de la clase del mensaje. Este metodo establece o despeja todos 10s indicadores del mensaje que se encuentran en este o b j e t o ~ag. l Cualquier indicador que se encuentre en 10s indicadores del mensaje que no esti en Cste, no seven afectados. Este mitodo establece el indicador dado en un estado dado.

boolean isset (Flags.Flag f l a g ) Flags getFlags ( )

void setFlags (Flags flag, boolean set) void setFlags (Flags.Flag f l a g , boolean set)

Cualquiera que haya escrito clases que hayan tenido que tratar con direcciones de e-mail de Internet conoceri 10s problemas asociados con todos 10s diferentes formatos que puede adoptar una direcci6n. En ocasiones puede resultar una pesadilla de anilisis. Cada mensaje tiene, como minimo, una direction asociada. La clase j a v a x .mail .Address es la clase utilizada para denotar esta direcci6n. Sin embargo, como podri comprender, cuando el API de JavaMail intenta realizar todas las funciones para cada sistema basado en mensajes, las direcciones pueden diferir notablemente entre sistemas. Por ejemplo, la direcci6n para un mensaje destinado a un grupo de noticias no es la misma que la destinada a una cuenta de e-mail de Internet. Por este motivo, la clase base j a v a x .mail .Address tiene muy poca funcionalidad con solo un minimo ntimero de metodos expuestos.

En cambio, las subclases proporcionan la verdadera funcionalidad. El API de JavaMail incorpora dos implementaciones:

Una direcci6n de e-mail debe contener una direccibn, opcionalmente con un nombre asociado a ella. Por ejemplo, las dos siguientes direcciones de e-mail son direcciones de e-mail vilidas:

Cuando tenemos mis de una direcci6n de e-mail para expresar, por ejemplo en el campo Para de una cabecera de mensaje, las direcciones se encadenan utilizando la coma como separador. Para analizar y encadenar continuamente direcciones de e-mail, el API de JavaMail proporciona una clase de ayuda:

Esta clase elimina todo el trabajo duro de esta tarea. Existen mCtodos para convertir la creaci6n y manejo de direcciones de e-mail en una tarea trivial:
I n t e r r ~ e t A d d r e s s M y 4 d d r e s s = new I n t e r n e t A d d r e s s ( ) ; MyAddress. s e t A d 3 r e s s ( " a l a n @ r ~ - a r y co . m") ; MyP,ddress. s e t F e r s o n a 1 ( " A l a n W i l l i a m s o n " ) ; S y s t e r n . o u t . p r i r l t l r 1 ( " M y A d d r e s s = " t MyAd\jress . t o S t r i n g ( ) ) ;

C o m o ya habri comprobado en las anteriores secciones, es muy raro que trabajemos con una Gnica direcci6n individual; la mayoria de las ocasiones utilizaremos listas o conjuntos de direcciones. C o n esta finalidad, Int ernetAddress dispone de mCtodos estiticos para que del anilisis de estas listas sea mis ficil:
IrtternetAddress taFie1.J. [

1nternetAddress.parse ( " a l a n @ n - a r y .corn, c e r i e n - a r y . corn"

);

for

( i n t x=O; x < t o F i e l d . l e n g t h ; x t t ) [ 3 y s t e r n . o u t . p r i r ~ t l r ~ ( " t o F i e l d [ " t x t." .] Address="ttoField[x] .getAddress ( ) ); System.out . p r i n t l n ( " t o F i e l d [ " t x t " ] F e r s o n a l = t t F i e l d [ x ] .getpersonal ( ) ) ;

Existe un derivado de InternetAddress .parse ( tolerancia del algoritmo de anilisis:


public

. ..)

que toma un valor Booleano para forzar la


a , boolean strict)

InternetAddress[] InternetAddress.parse(String

Si strict esti configurado con el valor false,entonces la lista de direcciones puede ser separada por espacios ademis de comas. Si strict esti configurado con el valor true,entonces la mayoria de las reglas establecidas en RFC#822 se cumplen. Utilizariamos este metodo si estuvieramos permitiendo a un usuario introducir una lista de nombres a la hora de crear mensajes de e-mail.

El direccionamiento del grupo de noticias difiere del direccionamiento de e-mail. U n mensaje de grupo de noticias tiene corno minimo un nombre de grupo de noticias, con un nombre de host optional. El API de JavaMail proporciona una implementaci6n para este con la clase javax mai 1.internet.NewsAddress.

JavaMail
Esta clase opera del mismo mod0 que la clase I n t e r n e t A d d r e s s analizada en la secci6n anterior, proporcionando mktodos para un ficil manejo de direcciones individuales y listas de direcciones:
N e w s A d d r e s s myNews = new N e w s A d d r e s s ( " c o r n p . l a n g . j a v a . P L - o g ~ ~ a r n r n e ) r ;" MyNews. s e t H o s t ( " n e w s . s u n . corn" ) ; S y s t e m . o u t . p r i n t l n ( " m y N e w s . r 1 e w s g ~ - o u p = " t myNews . g e t N e w s g r o u p ( ) ) ; S y s t e m . o u t . p r i n t l n ("myNews. h o s t = " t m y N e w s . g e t H o s t ( ) ) ;

Hasta el momento, hemos visto cdmo el API de JavaMail trata el mensaje individual y las propiedades y acciones asociadas a1 mismo. A continuacibn, examinaremos la gesti6n de mensajes y como JavaMail provee el manejo de grupos de mensajes. Los mensajes estan organizados en carpetas y estas carpetas estin contenidas en un h i c o almackn. Por defecto, un almackn debe tener como minimo una carpeta en la que 10s mensajes puedan residir. Este requisite permite a1 API de JavaMail proporcionar un mCtodo de acceso uniforme en todos 10s diferentes protocolos. Por ejemplo, el protocolo P O P no cuenta con la nocion de carpetas y simplemente almacena sus mensajes como lista. Pero, en beneficio de la abstraccicin, cualquier implementaci6n del protocolo P O P debe proveer la carpeta INBOX. Antes de acceder alas carpetas, debemos primer0 obtener una instancia de objeto j a v a x . m a i l . s t o r e , normalmente del objeto j a v a x . m a i l . s e s s i o n analizado previamente en el capitdo. La clase s t o r e proporciona 10s mktodos de acceso a la jerarquia de carpetas y autentifica la conexion si asi fuera requerido por el protocolo subyacente. Una instancia de objeto s t o r e puede ser recuperada de la instancia s e s s i o n en cualquier de las siguientes formas:
public public public public Store Store Store Store getstore () g e t s t o r e (Provider provider) getstore (String protocol) g e t s t o r e (URLName urlname)

La primera versi6n de g e t s t o r e ( ) utiliza el protocolo predeterminado especificado en la propiedad de sistemamail . s t o r e . p r o t o c o l , para crear el objeto s t o r e . La segundaversi6n utiliza la instancia provista Provider para crear y devolver una instancia. La tercera versi6n nos permite utilizar otro protocolo distinto al protocolo predeterminado especificado en el objeto p r o p e r t i e s utilizado para crear S e s s i o n , mientras que la cuarta version utiliza un objeto especial, URLName, para crear el objeto S t o r e . Una vez hayamos obtenido el objeto s t o r e , necesitamos conectar a1 almackn de correo antes de empezar a recuperar y emplear las carpetas. Esto se consigue con una h i c a llamada al mktodo c o n n e c t ( . . . ) , pasando 10s detalles necesarios de autentificaci6n si asi fuera requerido por el almackn subyacente. El siguiente fragment0 de c6digo ilustra una situaci6n tipica para recuperar el objeto s t o r e para conectar a un servidor POP:
/ / Confiyurar 10s par6metros predeterminados P r o p e r t i e s p r o p s = new E ' r u p e r t i e s ( ) ; props.~p( t " m a i l . t r a n s p o r t . p r ~ t o c o l " , "pop" ;
1 1 Crear l a session Sesslon mailSession , ,

y
=

c r e a r un n u e v o m e r l s a j e d e c o r r e o Session.getInstar~ce(~~ri~ps);

/ / O b t e n e r e l c ~ b j e t o S t o r e y c o n e c t a r curt e l s e r v i d o r Store mailstore = rnailSession.getStore ( ) ; m a i l s t o r e . c o n r ~ e c( t " y r ~ u r p o p . s e r v e r . c o m " ,110, " y o u r n a m e " , " y r ~ ~ ~ r p a s s w c r r; d")

Capitulo 13

//

Proceder

rnanipular

carpetas

El metodo connect ( . . . ) tiene una serie de variedades que dependen de la autentificacion requerida. Si fallara la conexion a1 almacen de mensajes subyacentes, el mitodo connect ( . . . ) genera la exception
javax.mail.AuthenticationFailedException.

En este punto, la instancia store esti preparada para el uso, dando acceso a la base de datos de la carpeta.

Acceso a las carpetas


A travks del objeto store recuperamos referencias a sus carpetas. Una carpeta es representada con la clase j avax .mail . Folder y sera analizada en la siguiente section. Por defecto, el objeto store debe proveer
como minimo una carpeta. Esto se debe a1 hecho de que algunos servicios de correo no se adaptan en absoluto a la noci6n de carpetas y esto mantiene una capa de abstraction para el API de JavaMail. Esto garantiza que no existan casos especiales, independientemente del protocolo de correo. Los metodos de acceso a carpetas estin resumidos en la siguiente tabla:

Folder getDef aultFolder ( ) Folder getFolder (String name )

Recuperar la carpeta de nivel superior o raiz para el almackn. En la instancia del protocolo POP, es la carpeta INBOX. Devuelve lacar etadentrodelalmackn, con independenciade si existe o no. P o emos entonces invocar sucesivamente el mitodo Folder. exists ( ) paradeterminar suestado. Esto resultalitil cuando deseamos crear nuevas carpetas.

Folder getFolder (URLNarne name ) Folder [ ] getPersonalNamespaces ( ) Folder [ I getUserNamespaces (String user)

Similar a1 metodo anterior, except0 en que la carpeta se direcciona utilizando el o b j e t o ~ ~ ~ ~ a m e . Devuelveunamatriz de carpetas que son consideradas accesibles por el usuario actual. Devuelve una matriz de carpetas son consideradas accesibles por el usuario actual y el usuario pasado. Este metodo apoya la nocion de que un gestor puede haber otorgado diferentes pr,ivilegios de acceso, por ejemplo,a su secretaria y a otros miembros del equipo. Este mitodo devuelve una matriz de carpetas consideradas accesibles para todos.

Folder [ ] getSharedNamespaces()

Por lo tanto, el codigo para acceder a la linica carpeta dentro del cuadro P O P para un determinado usuario seria el siguiente:
/ / O b t e n e r e l n b j e t o S t o r e y c o n e c t a r con e l s e r v i d a r ceri@wbibih . o t m a i l . corn") ; URLNarne ~ u r l n a r n e - new URLNarne ( " p o p 3 : / / a l a r ~ : Store mailstore = rnailSession.getStore(urlr~arne); rnailStore.connect();

// //

Prcceder a F<-~l,dei rn b o x

rnanipular l a s c a r p e t a s rnailStore.getDefaultFolder ( 1 ; entrada de Folder


=

r r

bandeja

de

r n a i l S t o r e . g e t F o l d e r ("INBOX") ;

Observe el uso especial de la palabra clave INBOX (bandeja de entrada). La palabra clave esti reservada y es un nombre especial para denotar la carpeta en la que el usuario recibiri sus mensajes. Observe que no

todos 10s protocolos ofrecen la carpeta INBOX.D e hecho, el protocolo de N N T P de grupo de noticias carece del concept0 de bandejas de entrada. Utilizando 10s mitodos mostrados, para acceder a las carpetas debemos conocer el nombre de la carpeta de antemano. Ademis, una carpeta puede contener tanto mensajes como carpetas. El objeto Folder nos ayuda en este descubrimiento o f r e c i h d o n o s algunos mitodos de acceso que nos permiten enumerar ficilmente todas las carpetas contenidas. Podemos hacer esto utilizando el mitodo:

Este metodo puede ser ejecutado en una carpeta cerrada y devolveri una matriz de todas las carpetas contenidas en la presente carpeta. S61o enumerari las carpetas de nivel superior de la carpeta y n o profundizari mis. Sin embargo, en algunos servidores de mensajes, ciertas carpetas pueden contener subcarpetas y s61o tener mensajes en ellas. Los grupos N T T P , por ejemplo, s61o pueden tener mensajes en ellos y n o en otros grupos de noticias. Por lo tanto, antes de realizar cualquier lista, es aconsejable comprobar que tal lista puede ser producida como ksta:
Folder listOfFc,l~iers [ I = r,,-~ll; 1 !thi-Fol'jrr.;letType ( 1 & F~il~der.HOLD -S FOLDERS) ) if 1 i s t O f F o l d e ~ c = t h i ~ F c ' l d e rl .i-t ( ) ;
[

C o m o hemos visto en este fragmento de c6dig0, el metodo getType ( ) de la clase Folder devuelve el campo de estado para esta carpeta, que es un campo de bit de numero entero con cada bit representando un determiilado estado. El estitico Folder.HOLDS-FOLDERS es s61o u n o de 10s estados en 10s que podemos realizar una comprobaci6n utilizando la funci6n hgica AND.O t r o s estados que podemos comprobar en una deterrninada carpeta incluyen la condici6n de la carpeta de "solo-lectura" (Folder.READ-ONLY), si la carpeta puede contener mensajes (Folder.HOLDS-MESSAGES), o si 10s contenidos de la carpeta pueden ser modificados (Folder.READ-WRITE). El objeto Folder n o se detiene aqui. Podemos utilizar una versi6n especializada del m i t o d o list ( . . . ) que nos permite pasar una cadena de busqueda para reducir o ampliar el grupo de resultados devueltos. P o r ejemplo, considere el siguiente ejemplo:
Folder ListOf Folders [ ]

t h i s F 8 , l ~ 3 e i .l . i s t ( " C l i e n t s % " );

Devolveria todas las carpetas contenidas en la carpeta actual, thisFolder,que ernpezaba con la cadena "Clients ". El % es el simbolo comodin que nos permite dar alcance a la carpeta actual. Considere ahora el siguiente ejernplo:
Folder 1 l s t O f F ' - ) l i e r s[ I t h i c f o l d e r . list ("C*") ;

Devolveria todas las carpetas, incluida cualquier sub-carpeta, que empiece por la letra C. El simbolo comodin * es similar a1 caricter % excepto que tambikn busca todas las sub-carpetas y, cuando es utilizado solo, puede enumerar todas las carpetas en una jerarquia completa, corno muestra el siguiente c6digo:
/ / C o r l f i g u r a r lc's p a r 6 r n e t r o s predeterrnitnadims P r c ' p e r t i e s p r ~ p : = new P r o p e r t i e ( ) ;

//

Crtzr l a session Sezsiorl rnailSession

y
=

rear u n n u e . i c m e n s a j e d e ~ o r r e o Cessir,r~i.getIrlstsr~ce prop.^) ;

/ / O b t e r i e r e l n h j r t o S t o r e y i o r l e c t a r curl el s e r v i d i ' r IJKLNarne u r l r ~ a r n e = n e w URLNarne ( " i m a p : / / a l a ~ ~ l : , : e r i e m a i . l r n i c r i . s ~ ~ f t . c o r n; ") S t o r e nlailStore = mailSissior~.grtStore(urlr~arnej; r n a i l S t o r e . c r ~ r 1 r ~ e (c )t ;

Capitulo 13
//
Proceder a l i s t a r todas l a s carpetas F o l d e r t h i s F o l d e r = mailStore.getDefaultFolder ( ) ; (thisFolder != null) { i f ( ( t h i s F o l d e r . g e t T y p e ( ) & F o l d e r .HOLDS FOLDERS) ! = 0 ) { Folder [ I 1istOfFolders = t h i s F o l d e r . l i s t f o r ( i n t x=O; x < 1 i s t O f F o l d e r s . l e n g t h ; x t t ) { S y s t e m . o u t . p r i n t l n ( " F o l d e r N a m e = " t 1 i s t O f F o l d e r s [x]. g e t N a m e ( ) ) ;

i f

Ademis de 10s mitodos l i s t ( . . . ) ,existen varios mitodos adicionales que limitan la busqueda a las carpetas a las que el usuario se ha suscrito. Dependiendo de si el servidor de mensaje a1 que estamos conectados puede o no adaptarse, podemos suscribirnos a una carpeta. En este punto, recibiremos notificaciones de cualquier cambio de estado en la carpeta:
Folder [ I Folder [ ] listSubscribed() listSubscribed(String search)

Recuerde que muchos de estos mitodos l i s t X X X ( . . . ) son inutilizados en algunas implementaciones de protocolo puesto que el almacenamiento subyacente no se adapta a ellos (como POP3, por ejemplo).

JavaMail ha introducido un plan de direccionamiento muy limpio y uniforme para ser utilizado a la hora de acceder a 10s sistemas de almacenamiento de correo, basado en la sintaxis URL. El formato, como podemos ver, no es distinto de la norma URL y encapsula toda la informacion requerida para acceder a un determinado recurso dentro de un servicio de correo:

La clase, j a v a x . m a i l .U R L N a m e , encapsula toda la funcionalidad para trabajar con estas direcciones, proporcionando 10s mitodos necesarios para construir y extraer determinada informaci6n. El API de JavaMail fomenta su uso como un plan de direccionamiento y veremos que muchos de 10s ntktodos la utilizan como direcci6n en oposici6n a transportar cinco piezas individuales de informaci6n. El siguiente ejemplo muestra como conectar con un servidor utilizando el objeto URLName:
/ / Configurar 10s parsmetros predeterminaosor P r o p e r t i e s p r o p s = new P r o p e r t i e s ( ) ; pro~> .p s u t ( " m a i l . t r a r ~ s p o r .tp r o t o c o l " , "pop"); / / Crear l a sessior, Session mailSession
y
=

defect0

c r e a r un n u e v o m e n s a j e d e c o r r e o S e s s i o n . g e t I n s t a n c e ( p r o p s );

/ / Obtener e l o b j e t o S t o r e y c o r ~ e c t a r con e l s e r v i d o r URLName u r l n a m e = new URLName ( " p o p 3 : / / a l a r ~ : c e r i @ w w w h. o t m a i l . corn") ; S t o r e m a i l s t o r e = m a i l S e s s i o n . g e t S t o r e ( u r l n a m e ); mailstore. connect ( ) ; //


Pruceder a manipular las carpetas

Veremos un uso extensivo de la clase U R L N a m e en las posteriores secciones cuando vayamos estudiando exhaustivamente c6mo interactuar con mensajes individuales en una carpeta determinada. La clase s t o r e expone un mitodo para obtener el U R L N a m e para una sesi6n: g e t U R L N a m e ( ) . Como probablemente se imaginari, esto puede suponer un problema de seguridad puesto que la contraseiia estara a la vista. Por este motivo, la informaci6n de la contraseiia no esta disponible a1 extraer el URLName.

j a v a n e t . URL. Aunque la funcionalidad ofiecida por URLName es rnuy similar a la disponible

Observe que esta clase, URLName, no tiene absolutamente ninguna relacidn con la clase

en la clase URL, es importante no confundir ambas clases.

Una carpeta es un contenedor de listas de mensajes. Las mismas carpetas pueden contener carpetas adicionales, proporcionando asi una estructura similar a un directorio para el archivo de mensajes. El prop6sito del objeto F o l d e r es facilitar la comunicaci6n y gesti6n de 10s mensajes. Las carpetas son por defect0 inicialmente recuperadas en estado cerrado y, antes de que se ejecute ninguna operaci6n que altere bisicamente 10s contenidos de la carpeta, primero es necesario abrir la carpeta. N o todas las operaciones requieren que la carpeta sea abierta. Por ejemplo, enumerar carpetas, renombrar la carpeta y controlar 10s nuevos mensajes son operaciones que pueden realizarse mientras la carpeta permanece cerrada. Una vez que la carpeta esti abierta, sin embargo, tambikn podemos recuperar mensajes, cambiar notificaciones y ejecutar cualquier otro tip0 de funcidn que ofrezca el objeto carpeta. Los mensajes de una carpeta son nombrados numkricamente desde 1 hasta el total de numero de mensajes de la carpeta. Es muy parecido al mod0 en que el protocolo P O P trata sus mensajes, con la numeration establecida en el orden en que son recibidos, siendo el numero mis bajo el mensaje mis antiguo. Sin embargo, no siempre se puede confiar en este orden y es mejor ordenar 10s mensajes de antemano, si asi fuera requerido por su aplicacidn. El numero de mensaje es fijado normalmente entre la apertura y posterior cierre de una carpeta. Al eliminar un mensaje, la numeraci6n de 10s mensajes no se actualiza hasta que tiene lugar la llamada e x p u n g e ( ) sobre el objeto F o l d e r . Cuando borramos una carpeta, todos 10s mensajes que han sido marcados para ser borrados serin finalmente eliminados de la carpeta y borrados. Despuks de esta llamada, el mensaje no seri recuperable, por lo menos desde esta carpeta. Debemos ser conscientes de que esto borrari permanentemente 10s mensajes marcados y provocari una renumeracidn de 10s mensajes de la carpeta. El registro de mensajes a travks de este esquema de numeracidn puede ser p~oblemitico y provocar resultados no deseados. Si es posible, debemos referirnos a1 mensaje utilizando la referencia Message.

Abrir y cerrar carpetas


Antes de que podamos enumerar mensajes, debemos primero situar la carpeta en estado abierto. Esto se realiza invocando:
void open(int mode)

El mitodo o p e n ( ) situari la carpeta en estado READ-ONLY o en ~ S ~ ~ ~ O R E A D - W dependiendo RITE, del mod0 pasado. La implementacidn subyacente es responsable de determinar si un mod0 particular es o no valido. Por ejemplo, algunas implementaciones, como IMAP, permitirin a multiples usuarios leer una determinada carpeta y, en algunos casos, incluso permitiri que multiples usuarios graben en la carpeta. Pero algunas implementaciones P O P probablemente no permiten varios lectores simultineos. Podemos comprobar si el estado de la carpeta ha sido abierto invocando el mktodo g e t T y p e ( ) ,por ejemplo:
if
]

...

(thisFolder.getType() == Folder. READ-ONLY) [ Systern.out .println ("This folder was optried with READ ONLY a c c e s s " ) ; else { Systern.aut.printlr~l"This folder was opened with R E A D - W R I T E a c c e s s " ) ;
-

Capitulo 13
Una vez se ha abierto una carpeta, podemos empezar a utilizar la mayoria de 10s mitodos de acceso. DespuCs de haber terminado con una carpeta, es mejor ejecutar unmetodo close ( . . . ) explicit0 para permitir que el protocolo subyacente limpie cualquier recurso en ese lugar y ese momento, en lugar de dejarlo para mis tarde para el recolector de residuos. El mCtodo close ( . . . ) toma un parimetro boolean adicional, que indica si debe o no llevarse a cabo una operation de borrado. Si el valor es true,entonces se invoca expunge ( ) , eliminado permanentemente cualquier mensaje marcado con el indicador Flag.DELETED. Quizis haya ocasiones en las que hemos pasado un objeto Folder y no estamos seguros del estado en que se encuentra. Podemos ficilmente determinar si esti o no abierto invocando:
boolean isopen ( )

Mensajes de listado
El objeto Folder esti diseiiado para albergar mensajes y, con ese fin, proporciona una rica lista de mitodos para recuperar mensajes alojados en la carpeta. Los mensajes son devueltos como listas, utilizando matrices. Los objetos devueltos pretenden ser ligeros en el sentido de que no toda la information sobre un mensaje se encuentra disponible de forma inmediata. Por ejemplo, si tuviCramos que recuperar 10s contenidos de una carpeta que albergara 10 mensajes, cada uno de ellos con un archivo adjunto de lOMB, la cantidad total no seria equivalente a 100MB. Observe que corresponde puramente a la implementxion del protocolo subyacente pero, en la mayoria de 10s casos, se adhiere a iste porque la noadherencia provocaria problemas con el ancho de banda y la gestion de memoria general. En la siguiente tabla, se presenta una breve descripcion de cada mitodo de recuperacih de mensaje disponible desde javax.mai1.Folder:

int getMessageCount ( ) boolean hasNewMes sages ( )

Devuelve el nlimero total de mensajes albergados en estacarpeta o -1 si el total no puede ser determinado p6r alglin motivo. Devuelve truesicualquieradelosmensajesalbergadosenlacarpeta tiene configurado el indicador Flag.RECENT. ladefinicionexacta de un nueva mensaje depende enteramente de la implementaci6n subyacente. Similar a1 mitodo anterior, except0 que devuelve el nhmero de mensajes que deben tener elindicador Flag.~ ~ ~ ~ N ! C c o n f i g u r a d o o - 1 si no puede ser determinado por alglin motivo.

int getUnreadMessageCount( Message getMessage (int index) Message [ ] getMessages ( ) Message [ I getMessages (int start, int end) Message [ ] getMessages (int index [ ] )

Devuelvetrue sicualquierade 10s mensajes albergados en lacarpeta no tiene configurado el indicador Flag. SEEN. Devuelve una version ligera del mensaje en el indice dado. Devuelve una matriz de todos 10s mensajes contenidos en esta carpeta. Devuelve una matriz de todos 10s mensajes contenidos en esta carpeta, incluida en el rango especificado por start y end. Devuelve todos 10s mensajes referenciados por la matriz de indices pasados.

El siguiente c6digo demuesira el listado de todos 10s mensajes de la carpeta P O P y el campo de asunto para cada uno de ellos:

696

JavaMail
/ / Configurar 10s parimetros predeterminados Properties props = new Properties ( ) ; Props.put("mail.trar~sp0rt.proto~01", " p o p " ) ; / / Crear la session y crear un rluevo mensaje d e correo ; Session mailSession = Session .getInstance ( p r o p s ) / / Obtener el objeto Store y conectar con el servidor ceri@www. hotmail. c o m " ); URLName urlname = n e w URLName ( " p o p 3 ://alar~: Store mailstore = mailSession.getStore(ur1r~ame); mailstore. c o n n e c t ( ) ; / / Proceder a obtener la carpeta Folder rootFolder = mailstore .getDefaultFolder ( Folder inbox = rootFolder. getFolder ( " I N B O X " ); inbox. o p e n ( Folder. R E A D O N L Y ) ;

) ;

Message [ I allTheMessages = inbox. getMessages ( ) ; for lint x=O; x < allTheMessages.1ength; x + + ) { System.out.prir.tln ("ID:" + x + " Subject:" + allTheMessages [XI .getSubject ( inbox.close(false); mailstore. c l o s e ( ) ;

) ) ;

Aunque JavaMail ofrece 10s rnetodos necesarios para deterrninar totales referentes a1 estado de la carpeta, n o siernpre se realiza de forrna eficiente. Por ejernplo, asurnarnos que quisierarnos contar 10s rnensajes entregados recienternente, por el metodo getNewMess agecount ( ) . Dependiendo de que el protocolo subyacente pueda proporcionar o n o esta funcionalidad, podria tener corno resultado una llarnada para recuperar todos 10s rnensajes y cornprobar despuks 10s estados de indicador del rnensaje individual. Lo que en principio era una llarnada inocente a algunas estadisticas numericas, se ha convertido es una operacion bastante costosa. C o n esa finalidad, es rnejor recuperar uno rnisrno 10s rnensajes y recorrerlos una vez, calculando todos 10s totales necesarios de una pasada.

Recuperation avanzada d e rnensajes


Corno hernos visto anteriorrnente, a1 solicitar una lista de rnensajes, obtenernos referencias ligeras a 10s datos reales del rnensaje, rnientras que 10s datos se recuperan y se invocan sus rnetodos de acceso. Por lo tanto, aunque tenernos una referencia a un Mens aj e,10s datos subyacentes para ese rnensaje quizis n o sean cargados realrnente en la rnernoria sino que pueden todavia residir en el servidor rernoto. Aunque, en conjunto, es un sisterna rnuy eficiente, hay casos en 10s que quizis deseernos solicitar explicitarnente que ciertas partes del rnensaje sean pre-cornpletadas con datos cuando sean recuperados del servidor. El API de JavaMail se ajusta este procedirniento a traves del uso de j avax .mail.FetchProfile,que enurnera 10s datos requeridos. La clase Folder proporciona el siguiente metodo:
void fetch (Message [ I messagelist, Fetchprof ile f Prof ile)

Por lo tanto, para una deterrninada lista de rnensajes, este rnetodo torna 10s datos dados para cada rnensaje:
FetchProfile fProfile = new Fetchprofile(); fProfile.add("To"); fProfile.add("From"); fProfile.add("Subject"); thisFolder.fetch(thisFolder.getMessages(), fprofile);

Capitulo 13
Este ejemplo crea una nueva instancia de F e t c h P r o f i l e y atiade 10s campos de cabecera de correo dados que quisiera recuperar del servidor para todos 10s mensajes de la llamada g e t M e s s a g e s ( ) . En nuestro ejemplo, buscamos 10s campos de c a b e c e r a ~ o F , r o m y S u b j e c t . Sin embargo, la clase F e t c h P r o f i l e sabe que la mayoria de usuarios quiere recuperar grupos de datos y, con este prop6sit0, puede solicitarse un grupo en lugar de especificar campos individuales. Los tres grupos de campos definidos para su uso con la clase F e t c h P r o f i l e son:
O

F e t c h P r o f i l e . 1tem.ENVELOPE Incluye 10s campos de cabecera comunes: De Para, C C O , Responder A, Asunto y Fecha. FetchProfi1e.Item.CONTENT-INFO Incluye la informacion referente a1 contenido per0 no el contenido. Por lo tanto, se toma informaci6n como tip0 de contenido, disposici6n, description, tamafio y total de lineas. F e t c h P r o f i l e . I t e m . FLAGS Todos 10s indicadores de estados para el mensaje.

Modificando nuestro ejemplo anterior, podriamos escribir:


FetchProfile f P r u f i l s = r~ewFetchProfilel); f P r r > f i l e . a d d ( F e t c h F r ~ 3 if l c . I t e m . E N V E L O P E ) ; t h i r K 1 1 d e r . f e t c h ( t l ~ i s F ~ ~ l . ~ e r . g e t M e s s( a) g , es fPri.fi1.1-I;

Copiar y mover mensajes


Probablemente, si un a l m a c h puede adaptarse a la noci6n de carpetas multiples, qermitirl la funci6n de copiar y mover mensajes entre diferentes carpetas. Para copiar una lista de mensajes, simplemente invocamos el siguiente mktodo de la clase F o l d e r :

Este metodo recorre la lista de mensajes y copia 10s mensajes dados, que deben ser parte de la carpeta actual, a la carpeta especificada. Los mensajes deben ser parte de la carpeta actual para permitir al lado servidor optimizar la transferencia a1 no tener que mover todos 10s datos a travks del cliente. Mover mensajes consiste sencillamente en copiar primer0 y marcar despuks cada mensaje con el indicador de eliminaci6n. Pero recuerde copiar 10s mensajes antes de eliminarlos, aunque la elimination no se ejecuta hasta que se borra la carpeta.

Buscar mensajes
Es importante trasladar al lado servidor la mayor parte del procesamiento y, por este motivo, una frecuente operacion que realizan las aplicaciones de lado cliente es buscar en sus almacenes de mensajes. El API de JavaMail proporciona una interfaz de busqueda muy sencilla para construir bGsquedas que pueden ser muy complejas en naturaleza. Se espera que la implementaci6n subyacente pase la busqueda a1 servidor para que Cste la ejecute. El objeto F o l d e r proporciona dos mktodos para busqueda de mensajes:
Message[] search(SearchTerm term) Message [ ] search (SearchTerm term, Message [ ] messagelist)

Estos mktodos devuelven una lista de mensajes que se corresponden con 10s criterios o, de no ser asi, una matriz vacia. Considere el siguiente ejemplo que enumera todos 10s mensajes procedentes de a l a n @ n a r y . comodecormac@n-ary.com:

JavaMail
SearchTerrn Message new O r T e r m (rlew F r o r n S t r i r l g T e r r n ( " a l a n @ n - a r y .corn" ) riew F r i i r n S t r i r ~ g T e r m ( " c o r r n a c @ r ~ - a r y corn" . ) ) ; m e s s a g e L i s t = t h i s F o l d e r . s e a r c h ( s t );
st
=

[I

El paquete j avax .mail.search proporciona un rico conjunto de clases que nos perrniten construir expresiones de blisqueda rnuy cornplejas. Construyendo la clase SearchTe rm,el API de JavaMail ofrece 10s siguientes operadores 16gicos:
0 AndTerm(SearchTe1m LHS, SearchTerm RHS)

AndTerm(SearchTerm items [ I
0

OrTerm(SearchTerm LHS, SearchTerm RHS) OrTerm(SearchTerm items [ I ) NotTerm (SearchTerm LHS)

Adernis de kstos, el objeto ComparisonTerm ofrece las siguientes constantes para construir cornparaciones nurnkricas:
0

ComparisonTerm.EQ Igual que ComparisonTerm-GE Mayor que o igual que ComparisonTerm.GT Mayor que ComparisonTerm. LE Menor que o igual que CornparisonTerm-LT Menor que ComparisonTerm.NE N o igual que

Los carnpos de rnensaje que pueden ser buscados incluyen:

0 0

FlagTerm(F1ags flags, boolean set) From~tringTerm(String pattern) FromTerm (Address add)

0 MessageNumberTerrn (int messageNumber) 0 0

ReceivedDateTerm(int comparison, Date date)


RecipientStringTerm(Message.RecipientTypetype, Stringpattern)

O SentDateTerm(int comparison, Date date)


0

SizeTerm(int comparison, int size)

Capitulo 13
Para ver algunos de estos detalles en accibn, examinemos ripidamente un ejemplo que, en la superficie, parece complicado per0 que, como veremos, es en realidad muy ficil de implementar. Asumamos que queremos buscar todos 10s mensajes procedentes de a l a n @ n - a r y . como de j a v a m a i l h e l p @ w r o x comque contengan la palabra JavaMail en algun lugar de la cabecera de asunto:

SearchTerrn

st1

new

OrTerrn(r1ew FrornStringTerni("alan@n-ary.cornU), new F r o r n S t r i r , g T e r r n ( " j a v a n r a i l h e l p @ w r o x .cf3rnm') ) ;

S e a r c h T e r n r s t 2 = new A n d T e r r n ( s t 1 , new S u b j e c t T e r m ( " J a v a t ~ l a i 1 " ) ) ; Messaqe[] rnessaqeList= t h i s F o l d e r . s e a r c h ( s t 2 ) ;

Como podemos ver, es una sencilla cuesti6n de construir la comparaci6n 16gica utilizando las diversas clases disponibles a travCs del paquete j a v a x . m a i l . s e a r c h .

La ultima clase de nuestro recorrido de exploraci6n en el API de JavaMail es la clase responsable de la entrega de niensajes, j a v a x . m a i l . T r a n s p o r t . La mayor parte del tiempo estaremos utilizando el protocolo SMTP para la entrega y, como ventaja, la clase T r a n s p o r t ofrece un metodo istitico para el envio de mensajes, como ya hemos visto anteriormente en este capitulo.
Tr:artspi,rt. s e r ~ d (rnsg)

Sin embargo, si deseamos un mayor control sobre la entrega del mensaje, consideremos el siguiente ejemplo que obtiene implicitamente la instancia especiiica del objeto ran sport, conecta manualmente despues ejecuta un envio sobre el mensaje:

T r a n s p a r t rnyTrarisport = s e s s i o n . g e t T r a n s p o r t ( " s n i t p " ); niyTransport. connect ( ) ; rnyTrarlspart. s e n d M e s s a g e (rnsg, rnsq.qetA11Recipierits ( ) ) ; rnyTrarispnrt. c l o s e ( ) ;


}

catch

(SendFailedException s f e ) {

Address [ I l i s t = s f e . g e t I n v a l i d A d d r e s s e s ( ) ; f o r ( i n t x=O; x < 1 i s t . l e r q t h ; x + + ) { S y s t e r n . o u t . p r i n t l n ( " I t ~ , v a l i dA d d r e s s : " + l i s t [ x ] ) ;


1

l i s t = sfe.getUnsentAddressesi) ; f o r ( 1 1 , tz = 0 ; x < 1 i s t . l e n g t h ; x + + ) { S y s t e r n . o u t . p r i n t l n ( " U r ~ s e r ~A t ddress:

"

l i s t [x]) ;

\
l i s t = sfe.getValidSe~~itAddresse ( ) s; f o r ( i n t x-0; x < 1 i s t . l e n q t h ; st+) { Systern.out.println("Sent A d d r e s s : "

listlx]);

I
La ventaja de este niecanismo, en oposici6n a la llamada estitica, consiste en que, si estamos enviando grandes cantidades de mensajes, el protocolo subyacente no tiene que seguir conectando con el servidor para cada mensaje; se utiliza la misma conexih. El rasgo que debemos tener en cuenta aqui es el bloque t r y .. c a t c h .

Si algo no funcionara, 10s metodos s e n d ( . . . ) generan una exception S e n d F a i l e d E x c e p t i o n con informaci6n completa de diagn6stico que nos ofrece la clave por la que las direcciones reciben una notificaci6n de entrega fallida. Tenemos a nuestra disposici6n tres listas de direcciones en caso de error: Address [ I getInvalidAddresses ( ) Devuelve las direcciones que no han recibido el mensaje debido a que dichas direcciones n o han podido ser resueltas a causa de, por ejemplo, un forrnato incorrecto.
0 Address[] getUnsentAddresses0

Devuelve las direcciones que n o han sido aceptadas para entrega. Por ejemplo, si el servidor no se adapts a1 reenvio, n o enviari un mensaje a un usuario fuera de su don~inio.
0 Address

sta as son las direcciones aceptadas para entrega.

[ I getValidSentAddresses ( )

Es importante destacar que, aunque un mensaje sea aceptado para su entrega, no existe garantia de que llegue a su destino final. Lo finico que puede garantizarse es la transmisi6n desde nuestra aplicaci6n hasta el servidor con el que e s t i comunicando la capa de transporte. Esto no indica necesariarnente una entrega satisfactoria el usuario final.

Trabajar con correo


Ahora que ya hemos recorrido todas las clases centrales y su relaci6n con respecto de la manipulaci6n de mensajes y carpetas, utilicernos estas clases en algunos ejernplos que demostrarin su uso. El prop6sito de esta seccion no es proporcionarnos un perfecto y completo cliente de correo (esa es su tarea), sino ofrecernos algo de experiencia prictica trabajando con ejemplos que nos muestra claramente qu6 e s t i sucediendo sin atestar el resto del programa con distracciones.

Todos 10s ejemplos de este capitulo son pequerias aplicaciones de lineas de comando. Son compilados y ejecutados con el nzinimo esfuerzo. Si esta' utilizando las librerias JZEE, compile sinzplemente desde la linea de conando utilizando el arcbivo j 2 e e . j a r , que sera'parte de su instalaci6n J2EE. De este modo, no necesita especificar explicitamente 10s arcbivos m a i l . j a r y a c t i v a t i o n . j a r . Alternativamente, si no esta' utilizando las librerias J2EE, necesitara' ariadir ambos archivos a su ruta de clase para compilar y ejecutar 10s ejemplos.

Probablemente, lo primero que querri hacer seri enviar algfin correo. Ya hemos visto, en este capitulo, c6mo enviar un correo bisico de texto sencillo utilizando el protocolo SMTP. Examinemos ahora una aplicaci6n que es alga mis funcional. La clase mostrada, j a v a m a i l . s e n d , torna cuatroparimetros: s m t p s e r v e r , t o E - m a i l , f r o a - m a i l y el c u e r p o del e-mail. Corno se puede ver, analizarnos 10s parimetros de lineas de comando y procedernos a configurar la sesidn para el servidor:
import import import import import java.uti1. * ; java.io.*; j avax.mai1. * ; j avax.mai1. internet. * ; j avax. activation. * ; extends Object
{

public class j avamail-send

Capitulo 13

public

static

void

rnain(Strir1q a r q s [ ] )
=

S t r i n g srntpserver S t r i n q toErnail S t r i n g frornErnai1 S t r i n q body

=
=

null; null; null; null;

//

A n a l i z a r 1 0 s p a r i r n e t r o s d e l i n e a d e Cornando x++) { f o r ( i n t x=O; x < a r q s . l e n q t h - 1 ; i f ( a r q s[ X I .equalsIqnoreCase ('I-S") ) { srntpserver = arqs[x+l]; 1 e l s e i f ( a r q s[ X I . e q u a l s I q n o r e C a s e ('I-T") ) { toErnail = a r q s [ x t l ]; ] e l s e i f ( a r q s[ X I .equalsIqnoreCase ("-F") ) { frornErnail = a r q s [ x t l ] ; } e l s e i f ( a r q s [ X I . e q u a l s I q n o r e C a s e ('I-B")) { body = a r g s [ x t l ] ;

if

( s r n t p s e r v e r == n u l l I I t o E r n a i l == n u l l I I frornErnai1 == n u l l 1 I b o d y == n u l l ) { S y s t e r n . o u t . p r i n t l n ( " U s a q e : j a v a r n a i l s e n d -S < s e r v e r > -T < t o e r n a i l > -F < f r o m > -B < b o d y > " ) ; System.exit(1);

try

1
//
Confiqurar 10s parirnetros predeterrninados P r o p e r t i e s p r o p s = new P r o p e r t i e s ( ) ; props.put("rnail.trar~sporttprotocol", "srntp"); props.put("rnail.srntp.host", s m t p s e r v e r ) ; props.put("rnail.srntp.port", " 2 5 " ) ;

//

C r e a r l a s e s s i o n y c r e a r un n u e v o r n e n s a j e d e c o r r e o Session mailsession = Session. get1nstance (props) ; M e s s a g e msq = new MimeMessaqe ( m a i 1 S e s s i o n ) ;

//

C o n f i q u r a r 1 0 s carnpos DE, PARA, FECHA y ASUNTO rnsq. s e t F r o r n ( n e w I n t e r n e t A d d r e s s ( f r o r n E m a i 1 ) ) ; rnsq.setRecipients(Messaqe.Recipier~tType.TO, I n t e r n e t A d d r e s s . p a r s e ( t o E m a i 1 )) ; rnsq.setSentDate (new Date ( ) ) ; msq. s e t s u b j e c t ( " T e s t M a i l " ) ; correo

//

Crear e l cuerpo d e l r n s q . s e t T e x t ( b o d y ); T r a n s p o r t . s e n d ( m s g );

I I

catch (Exception e ) { Systern.out.println(e);

I
Crearnos el rnensaje de e-mail de la forrna habitual utilizando la c l a s e ~ i m e ~s easg e con tan poca inforrnaci6n corno sea necesaria. Despuks de que todas las propiedades necesarias de 10s rnensajes estkn establecidas, utilizarernos el rnktodo estitico T r a n s p o r t . s e n d ( . . . ) para entregar el rnensaje. Es aside sencillo.

Despues de conlpilar nuestro cbdigo Java, asegurlndose de incluir el/los archivo(s) J A R e n la ruta de clnse, podemos ejecutnr nuestro programs. Asi deberia quedar la v e n t m a de linea d e comandos que muestra 13 salida de nuestro sencillo j a v a m a i l - s e n d p r o g r a m

Al find de nuestro progralna, realizamos un simple vaciado del ~nensaje central realizando una Ilamada a M e s s a g e . w r i t e T o ( . . . ) ,quc debe producir un e-mail con un mensaje similaral siguiente:

Observe la presencia de Ins cabecerns y la composici6n del e-mail, c o m o hemos visto antes e n este cnpitulo.

Enviar documentos adjuntos


Despuks de hnber visto lo sencillo que resulta enviar un e-mail bisico, vearnos c 6 m o enviar algo un poco m i s complicado: nnesos de nrchivos. N o s hemos referido ya a este tema y hemos reparado e n que debemos construir el sistema utilizando una serie de diferentes cuerpos MIME. u n o representando el texto del mensaje y el o t r o albergando la informacibn necesaria para el archivo que deseamos enviar. T o m a n d o el ejemplo d e la secci6n anterior, necesitaremos atiadir un parimetro extra para indicar el archivo ajunto y reemplazar el anterior t r y c a t c h , como muestra el siguiente extract0 de cbdigo. El codigo de fuente completo para este ejemplo puede encontrarlo en el archivo j a v a m a i l - s e n d - a t t a c h m e n t .j a v a , disponible, junto con todo el c6digo fuente de este libro, enwww.wrox c o m

...

Capitulo 13
S t r i n g kody String file
= =

null; rd~ll;

//
f

A r ~ a l i z a r 10s p a r d m e t r u s d e l i r l e a d e cornando ~ ( r i n t s = O ; ;i < a r g s . l e n g t l 1 - 1 ; xi+) { i f ( a r g s[ X I . e q u a l s I g r ~ o r e C a s e ( " - S " ) ) { smtpServer = args[s+ll; } e l s e i f ( a r g s [ X I .equalsIqnoreCase ("-T") ) { tuErnail = a r g s [ x t l ] ; ) e l s e i f ( a r g s [ s ]. e , y u a l s I g r ~ o r e C a s e ("-F") ) fromErnaii = a r g s [ x t l ]; ] e l s e i f ( a r q s [ x ] . e q ~ u a l s I g r ~ o r e r a( s"e- B " ) ) { body = args[xtl]; } e l s e i f ( a r g s [ x ] .equalsIgnoreCase ("-A") ) { file = args[xtl];

1
if ( s r n t p s e r v e r == n u l l I l t o E m a i l == r l u l l I I f r o m E m a i 1 == r i u l l I 1 b o d y == r l u l l I I f i l e == r i u l l ) { S y s t e m . o u t . p r i n t l n ( " 1 J s a g e : j a v a r n a i l s e n d a t t a c h m e n t -S < s e r v e r > -T < t o e r n a i l > - F < f r o m > - B < b o d y > -A < f i l e > " ) ; System.rzit(1);

i
try

i / / C o n f i g u ~ - a rl o s p a r d m e t r o s p r e d e t e r r n i n a d , , ~
P r o p e l - t i e s p r o p s = rlew E ' r o ~ ) e r t i e (s ) ; proF).c . ~ ' u ( t " m a i l . t r a n s ~ p r .t ~ 8 r o t o c ~ ~ " ~s l m "t ,p " ) ; Flr6p.c . p l ~ 1t " m a i l . s r n t F , . h ( 7 s t " . s m t p S e r v e r ) ; ~ ' r . p 1 ? . p u t ( " m a i l . s m t p . p o r t W , "25") ;

//

C r r a r l a s e s s i o r , y r r e a r un n u e v e nrerlsaje d e c o r r e o S e s s i o n r n a i 1 S e s s i ~ : z r l = Session.getInstance(pro~~s); M e s ~ a q e msg = new M i r n s M e s c a , ~ ( er n a i l S e s s i u n );

//

C o r c f i g u r a r 1c.s camF,os DE, PARA, FECHA y ASUtJTO ; r n s g . s e t F r o r n ( r , e w I n t e r n e t A d d r e s s ( f r o ~ , E m a i l) ) m s g . s e t F : e c i ~ ~ i e r (~ M te s s s a , q e .R e c i ~ , i e n t T y ~ TO, >e. InternetAdd~ess . p a r s e (toEmai1) ; r n s g . s e t S e r t t L a t e ( r ~ e wD a t e ( ) 1 ; n : s g . s e t S u b j e c t ("TesL Mail w i t h a t t a c h r n e r ~ t " ) ; parte new M i m e l h i t i p a r t ( ) ;

//

Crear l a primera M u l t i p a r t mailBo,3y

M i m e B o a y P a r t r n a i r ~ B o d y = new M i r n e B o d y P a r t ( ) ; rnainBody.setText ( b o d y ) ; mailBod71~. a d d & > d y F a r t (mainBody);

//

C r e a r l a segunda p a r t e F i l e D a t a S o u r c e f d s = new MirneBodyPart m i m e A t t a c h = minieAttach. s e t D a t a H a r d l e r

c o n e l arlexo FileDataSource ( f i l e ) ; new M i m e B o d y F a r t ( ) ; (new DataHandler ( f d s )) ;

mimeAttach.setFileNarr~e(fds.getName()) ;
r n a i l B o d y . a d d B o d y P a r t ( m i r ~ e A t t a c h; )

//

Crear e l cuerpo d e l correo rnsg. s e t c o n t e n t ( m a l l B n d y ) ;

T r a n s p o r t . serld ( r n s g ) ;

JavaMail
System.out .prir~tln ("The e-mail below was ser~t successfully"); msg.writeTo (Systern.outj;

Puesto que este rnensaje tiene dos partes diferentes, necesitarnos crear el cuerpo del rnensaje central con una c l a s e ~ i m e ~ u ip l ta r t . Esto nos perrnite reunir las diversas partes del e-mail, tarea que realizarernos sucesivarnente. La prirnera es el cuerpo del rnensaje y, con ella, utilizarnos la c l a s e ~ i m e ~ o d y ~ para art albergar el texto del rnensaje, que despuCs afiadirnos a la i n s t a n c i a ~ i m e ~ u i lpt a r t invocando a d d B o d y P a r t ( . . .) . El archivo adjunto es la siguiente fase del problerna a1 que debernos enfrentarnos. Lo utilizarnos creando otra instancia d e ~ i m e ~ o d y ~ a que r t seri , utilizada para albergar nuestro archivo adjunto. La clase del Sisterna de Activaci6n JavaBean, F i l e D a t a S o u r c e , es utilizada para rnanejar el anexo para el archivo. Cuando la utilizarnos para crear nuestra instancia D a t a H a n d l e r , que es utilizada entonces para establecer art. configurar el nornbre del archivo adjunto con el rnanejador de datos en la c l a s e ~ i m e ~ o d y ~ Podernos una llarnada desde la clase F i l e D a t a S o u r c e . Corno antes, tornarnos esta i n s t a n c i a ~ i m e ~ o d y ~ yala rt afiadirnos a la lista de las partes que estin siendo rnanejadas por la i n s t a n c i a ~ i m e ~ u i lpt a r t . Finalrnente, tornarnos la instancia MimeMul t i p a r t y configurarnos el cuerpo principal del rnensaje para este objeto con l a l l a r n a d a m ~s ~e .tcontent ( .) .

..

Por rnera curiosidad, exarninernos ripidarnente el rnensaje de e-mail resultante. Analizando el siguiente rnensaje, podernos ver que la cabecera del correo es rnuy parecida; s61o ha sido alterado el T i p o d e C o n t e n i d o para reflejar que es un rnensaje rnultiparte, donde cada parte del rnensaje esti separada utilizando una cadenas generada de forrna exclusiva, corno:

describen la cornposicidn de Si busca esta cadena, veri otro conjunto de cabeceras de C o n t e n i d o . datos de una deterrninada seccion. Fijese en la parte que rnaneja el archivo adjunto. Describe toda la inforrnaci6n que ha sido utilizada para codificar 10s datos binarios para el archivo adjunto, en este caso en base64. El API de JavaMail rnaneja por nosotros la creaci6n de correo. Corno podernos ver, el forrnato cornpleto del archivo es relativarnente claro. Ir6nicarnente, una de las partes rnis espinosas es la eleccidn de una cadena lirnite para las partes MIME. N o debe aparecer corno parte de 10s datos para cada seccibn; de no ser asi, el algoritrno de anilisis utilizado para decodificar el rnensaje se confundira.

st as

Capitulo 13
Podemos compilar y ejecutar el programa d e la forma habitual; aqui tiene una muestra de la salida:

Ahora que ya hemos comprobado lo ficil que es enviar mensajes y anexos, examinemos otro aspect0 de la gesti6n de correo: leer mensajes.

Leer correo
Recibir un e-mail es tan sencillo con10 enviarlo, siempre que sigamos 10s pasos adecuados. Teniendo esta idea en mente, hay una serie d e hechos que podemos demostrar. C o n el siguiente ejemplo, ilustraremos 10s conceptos principnles del tratamiento del correo, construyendo una sencilla herramientn de acceso de linea de comando para correo POP3. Seri una herramienta muy sencilla: sin demasiadas complicaciones y que, con toda probabilidad, n o reemplazari a nuestros clientes Outlook o Eudora. Asi que n o espere demasiado de ella. En esencia, enumerari todos 10s mensajes contenidos en un servidor P O P y permitiri al usuario interactuar con esta lista. Pero, en primer lugar, construyamos un sistema para esta aplicacibn:
j a v a . u t i 1 . '; java.io.*; i m p o r t javax.mai1.'; import javax.mail.internet.+; import javax.activatinn. *; p u b l i c c l a s s j a v a m a i l pop e x t e n d s O b j e c t p u b l i c s t a t i c void m a i n l S t r i n g if args [ l
)

import import

i
(

(args.length ! = 1) ( System.out . p r i n t l n ( " U ~ a a g ~ , : j a v a m a i l pup < u r l n a m e > " S y s t ~ m . e x i t(1);


;

) ;

1
U R L N a m e u r l n a m e = n e w U R L N a m e ( a r g s [Oj )

try i / / Configurar 10s parsmetros predeterminados Properties props = n e w Properties ( ) ; props. put ( " m a i l .transport. ~ : r o t o c o 1 " , "pop" ) ; props.put("mail.pop.port", "110");
//

Abrir la sesihn S e s s i o n s e s s i o n = Session. getInstarice ( p r o p s ) ; Store s t o r e = sessior,.getstore (urlr~ame); s t o r e .c o n n e c t ( ) ;


/ / Abrir la carpeta Folder folder = store .getDefaultFolder ( ) ; if (folder == null) { System.out .println("Problem occurred"); System.exit(1);

; Folder popFolder = folder.getFolder ( "IhlBOX") popFolder. operc ( Folder. R E A D O N L Y ) ;

System.out .println("Opened with: Buf feredReader cmdPrompt


=

"

+ popFo1der.getMessageCount

( ) ) ;-

n e w BufferedReader ( new InputStreamReader (System.in) )

displayMessages (popFo1der) ; for(;;) 1 System.out .println ("Enter command (exit t o end) " ) ; System.out .print ( " % " ) ; String cmd = cmdPrompt. readline ( ) .toLowerCase ( ) ; if ( c m d .equalsIgnoreCase ( " e x i t " )) I break; } else I displayMessages(popFo1der);
}
i

popFolder.close(false); store. c l o s e ( ) ;
)

catch (Exception e ) [ System.out . p r i n t l n ( e );

I
1
Mostrar la lista d e rnensajes d e la carpeta dada. Mostrar solo el id. del mensaje, 10s campos d e y asunto private static void displayMessages(Fo1der folder) throws Exception Message[] 1istOfMessages = folder.getMessages(); Fetchprofile fProfile = n e w Fetchprofile(); fProfile.add(FetchProfile.Item.ENVEL0PE); folder.fetch(listOfMessages, fprofile); System.out .println ("Message List:") ; for (int x=O; x < 1istOfMessages.length; x++) I StringBuffer s b = n e w Strir~gBuffer (32);
//
// //

El id. del mensaje empieza desde 1

Ejecutarnos esta aplicaci6n desde la linea de cornando pasada en el string URLName que describe toda la inforrnacicin necesaria para conectar con el servidor POP3. Por ejernplo:

La primera tarea que r e a h a esta aplicaci6n es crear una instancia de la c h s e U R L N a m e y utilizarla para obtener acceso al objeto s t o r e que alberga la jerarquia de carpetas. Una vez que contamos con esto, podemos entonces obtener la carpeta de nivel superior, que nos perrnitiri acceder a la carpeta especial INBOX (la unica carpeta vilida para el protocolo P O P ) . A continuaci6n le mostramos un ejernplo de salida de pantalla del propio servidor de prueba P O P 3 del autor:

Utilizarernos una sencilla interfaz de tip0 linea d e cornando que utilice ~ n p u t s t r e a r n d e s y s t e m . i n . C r e a n d o una instancia d e o b j e t o B u f f e r e d R e a d e r , podemos buscar ficilmente cornandos cornpletos invocando sirnplemente el mktodo r e a d L i n e ( ) . Insertindolo e n u n ciclo continuo, podernos tener ficilmente mhltiples coniandos y perrnitir que el usuario abandone la sesicin i n t r o d u c i e n d o e x i t. U n o de 10s rnktodos fundarnentales de esta aplicaci6n es d i s p l a y M e s s a g e ( . . . ) . Este metodo toma la carpeta en cuesticin y enumera todos 10s mensajes contenidos en ella, mostrando el ID del rnensaje, el campo D e y el asunto de cada mensaje.

O t r o punto que merece la pena destacar en el uso de la clase F e t c h p r o f i l e . iRecuerda para qu6 servia? Se utiliza para completar en el mensaje ligero toda la informacibn necesaria referente a la cabecera del mensaje. Despuks de la llamada para completar la informacibn, simplemente ejecutamos el ciclo del mensaje para extraer la informacibn necesaria. La siguiente fase consiste en ahadir a nuestra aplicacibn de linea de comando la funcionalidad para rnostrar el contenido de un determinado I D de mensaje. Lo primer0 que necesitamos es ahadir la funcibn para procesar el comando d i s p l a y < i d > . Realizamos la adicibn necesaria para que el ciclo central f o r tenga este aspecto:
for(;;) i System.out .println ("Enter command (exit to e n d )" ) ; System.out .print ( " % " I ; String cnrd = cndPrr nrpt . readLine ( ) . toLowerCase ( ) ; if (crnd.equalsIgnirec'ase ("exit")) { break; ) else if (cnrd.ir~dexOf ("display") == 0 ) [ disp1aySir~glF;MF;ssage (popFolder, c m d ) ; } else { disp1ayMessagF;s( p o p F o l d e r );

Simplernente busca la palabra clave d i s p l a y y, cuando la encuentra, invoca el metodo d i s p l a y S i n g l e M e s s a g e ( . . . ) como detallamos a continuacibn. Este metodo analiza entonces el I D del rnensaje e intenta recuperar el mensaje en un indice determinado invocando el metodo g e t M e s s a g e ( . ) . Despuks de esto, el mensaje es escrito en el flujo de salida invocando simplemente el rnetodowrite~o ( ) :

. . . ..

private

static void displaySingleMessage (Folder folder, String crnd) throws Exceptior, { ir~t cl = cmd.indexOf(" " ) ; if ( c l == -1) 1 Systern.out .println ( " d i s p l a y < i d > " ) ; return;

int messageIP Message mess

= =

1nteger.parseInt (crnd.substring ( c l t l )) ; f~lder.getM?ssaqz(messageID);

N o es necesario ser un genio de Java para darse cuenta de que esta aplicaci6n esti llena de trampas. Hay muy poca funcionalidad en ella a la hora comprobar que el id. del mensaje se encuentra en realidad en el rango enumerado por la carpeta. Ademis de esto, permitiendo sirnplemente que el bloque t r y / c a t c h genere y capture la excepcibn, el manejo de errores es algo rudirnentario. Aqui vemos el palabra clave d i s p l a y en funcionamiento:

Capitulo 13

Recuerde que el prop6sito de esta aplicaci6n no es construir un cliente POP nbsolutamente sdlido si ilustrar algunos principios bisicos de Java.

Eliminar correo
Ampliemos nuestro cliente pop para incluir la capacidad de elirninar un mensaje de la carpeta. Podenios simplemente afiadir a1 ciclo de rnensaje la capacidad de rnanejar el cornando d e l e t e < i d > que, a su vez, invocael r n t t o d o d e l e t e s i n g l e M e t h o d ( . . .) ,de este rnodo:
f,:*r-(;;)
(

S~jsrem.~-~ut.~~rir~tlrt(" co Em rm ~ atne dr ( e x i t t o e n d ) " ) ; System.nut . p r i n t l " B " 1 ;


String

if
)

1
)

cmd = c r n d f r o m p t . r e a d l i n e ( ) Icrn.3. e ~ ~ u a l s I g n o r e r 3 a ( s" ee x i t " ) ) break; else i f ( c m d . i n d e x O f [ " d i s p l a y " ) displaySir~gleMes.saqe (popFolder, e l s e if ( cmd.ir~dex0ft"delete") deleteSirlqleMessage ( popFolder, else { displayMessages(p@pFolder);

.toLi3werCasto
{ == 0 ) ( crnrl) ; == D ) ( cmd ) ;

I Este metodo analiza el ID del rnensaje y recupera ese rnensaje. Desearnos elirninar este rnensaje y, corno ya sabemos de secciones anteriores, no existe para ello un rnttodo explicito. En su lugar, tenernos que configurar el indicador DELETED con el valor t r u e y desputs, cuando la carpeta se cierre, el rnensaje con este indicador ser6 elirninado. Este es el aspect0 de nuestro nuevo rnttodo:
private s t a t i c v o i d deleteSingleMessage(FoIder f o l d e r ,
(" ") ;

S t r i n g cmd) throws Exception

i r ~ tc l = cmd. i n d e x o f i f ( c l == -11 {

System.out.println("de1ete return;

<id>");

~ n r tn e s s a g e l D Message mess

= =

1nteger.parseInt (crnd.substrir~g ( c l t l )) ;

f~lder.getMessage(rnessageID);
true);

m e s s . s e t F l a g ( F l a g s . F l a g .DELETED,

S y s t e r n . o u t . p r i n t l n ( " D e l e t e d r n e s s a g e \ r \ n U );

I Si ejecutamos este c6digo tal y como estd ahora, descubriremos un pequeiio probfema de implementaci6n: que no funciona. El mensaje no se elimina. iPor q u i ? Realmente el motivo es muy sutil y es este tipo de pequefios problemas 10s que tenemos que identificar a1 trabajar con carpetas. Inicialmente, hemos abierto la carpeta en el mod0 READ-ONLY. Este paso bloquea efectivamente todas las modificaciones realizadas a la carpeta y a todos 10s mensajes contenidos en ella. Cambiando el mod0 de apertura, como mostramos a continuacion, podemos hacer que nuestra aplicaci6n reviva con la capacidad de eliminar mensajes:
p c r p F o l d e r . o p e n ( F ~ o l d e rREAD-WRITE) . ;

Recibir archivos adjuntos


Existe una pieza final de funcionalidad que es preciso aiiadir y es la capacidad de guardar archivos adjuntos en nuestro disco. Aiiadiremos el comando s a v e <id> que buscara un determinado mensaje, veremos si tiene algun anexo asociado y 10s guardaremos sucesivamente, en el disco (en;el directorio actual). Como ya hemos hecho antes, modificamos el ciclo principal de procesamiento de comandos para buscar el comando s a v e e invocar el nuevo metodo:
}

e l s e i f ( c r n d . i r ~ d e x O f ( " s a v e " ) == 0 ) s a v e A t t a c h r n e r i t ( p a p F o l d e r , crnd ) ;

private

static

void

saveAttachrnent(Fo1der folder,

S t r i n g crnd) t h r o w s E x c e p t i c ' r ~{

i n t c l = crnd. i n d e x o f ( " " ) ; i f ( c l == - 1 ) { Systern.cut . p r i n t l n ("save returrt;

< i d > ") ;

I
i r ~ tr n e s s a q e I D Message mess
= =

1 n t e g e r . p a r s e I r l t ( c m d . s u b s t r i r i g ( c l t l )) ;

folder.getMessage(rnessage1D);

Multipart for

multipart

( M u l t i p a r t ) r n e s s . g e t C o r ~ t e r I( t ) ;
it+) {

( i r i t i=O, n = m u l t j p a r t . g e t C o u n t ( ) ; i<n; Part p a r t = rnultipart.qetBodyPart ( i ) ;

String disposition = part .getDisposition ( ) ; i f (disposition != n u l l && ( d i s p o s i t i o n . e q u a l s ( P a r t .ATTACHMENT) I I

disposition.equals(Part.INL1NE))) {
FileOutputStrearn outFile in
=

new new

FileO~tp~tStrea~(part.getFi1eName());
Buf f e r e d I n p u t S t r e a r n

Capitulo 13
BufferedIr~putStream(part.getIr~putStream(~ ); int c; while ( ( c = i n . r e a d O ) ! = -11 I outFile.write(c);

1
outFile. close ( ) ; System.out.println("Attachmer~t: "+part .qetFileName()t " written"
) ;

I
1

1
A1 igual que con nuestros otros mitodos, analizarnos el id. dado y recuperarnos ese mensaje de la carpeta. A continuaci6n, asurnirnos que nuestros anexos del rnensaje serin parte de un mensaje m u l t i p a r t / * y n o aparecerin de forma independiente. Puede que esto n o siernpre suceda asi puesto que podemos enviar un rnensaje solarnente con el archivo adjunto y sin texto que lo acornpaiie. Despues de haber descubierto que el tipo MIME es en realidad u n m u l t i p a r t / * de a@n tipo, enviarnos el contenido de nuestro mensaje a un M u l t i p a r t y recorrernos la lista de partes. Exarninarnos la disposicion del rnensaje y si esti marcada con ATTACHMENT o un INLINE,entonces se guards en el disco. Guardar un archivo consiste simplernente en leer un byte del flujo de entrada y grabarlo en una clase F'i 1e ~itre r apropiada. Recuerde que el c6digo fuente cornpleto para este ejernplo y todos 10s dernis ejernplos de este capitulo, estin disponibles para su descarga enwww. w r o x . c o n

Guardar y cargar correo


Podemos utilizar el API de JavaMail para una gran cantidad de aplicaciones relacionadas con correo electronico y, una de las cosas que quizis deseernos realizar es guardar un deterrninado e-mail en una base de datos o en un archivo, para su posterior uso. Digamos, por ejernplo, que estuviirarnos escribiendo una aplicacion para enviar e-mail a un servidor de reenvio. i Q u i ocurre si el servidor de reenvio no esti disponible? iC6rno podernos almacenar en la rnernoria cache local estos e-mail hasta que el servidor de correo vuelva a estar on-line? Una vez tengamos nuestro e-mail representado en una instancia MimeMessage, pensariarnos que solo podriarnos codificarlo por medio de mitodos de codificaci6n de objetos Java. Sin embargo, estariarnos equivocados. El API de JavaMail no se ajusta a la codificacih de rnuchos objetos, siendo MimeMessage uno de ellos. El rnotivo de esto se encuentra en el numero de referencias externas que alberga la clase subyacenteMessage, por ejemplo s t o r e y S e s s i o n . Por ello, si el objeto ha sido restaurado de nuevo, tendri referencias n o vilidas. N o se asuste; la soluci6n esti cerca. La ticnica que utilizarnos para guardar y restaurar rnensajes de correo puede parecer algo extensa y n o rnuy eficiente pero, corno verernos, es la rnis sencilla de cornprender. Como ya hernos visto, un rnensaje de correo es sirnplernente texto ASCII sirnle, dispuesto de un rnodo conocido que cornprende una cabecera seguida de 10s datos o contenidos del mensaje. Para guardar un rnensaje, simplemente guardarnos la representacibn ASCII del e-mail finalrnente construido y lo situarnos en un archivo o base de datos. Para cargar de nuevo el mensaje, simplernente leemos el archivo de texto y pedimos al API de JavaMail decodificar de nuevo el rnensaje, corno si procediera del servidor de correo. Exarninimoslo en acci6n con una rnodificaci6n el ejernplo que hernos utilizado antes. En lugar de enviar un e-mail inmediatamente, lo guardarernos en el disco para enviarlo rnis tarde:
import j a v a . util. * ;

import irnpisrt import import public

j a v a . i o . '; j avax.rnail.+; javax.mai1. i n t e r n e t . + ; ja v a x . a c t i v a t i o n . *; class j a v a r n a i l -s a v e vcid extends Object


{

public

static

main ( S t r i n g a r q s j )
=
= = =

String String String String

smtpserver toErnail frornErnai1 body

null; null; r~ull; r~ull;

//

A r l a l i z a r 1 0 s p a r d m e t r o s d e l i n e a d e Cornando f a r ( i n t x=O; x < a r g s . l e r ~ g t h - 1 ; x t t ) { i f ( a r g s[ X I equals1gnoreCase ("-S") ) smtpServer = args [ x t l ]; 1 e l s e i f ( a r g s[ X I .e q u a l s I g r ~ o r e C a s e ('I-T" ) ) ( t a E m a i l = a r g s [ x t l ]; I e l s e i f [ a r g s 1x1 . e q u a l s I g n o r e C a s e ("-F") i [ fromEmai1 = hrg: [ x t l ] ; 1 e l s e i f ( a r g s [ x ] . e q u a l s I g n o r e C a s e ("-B")) { body = a r g s [ x t l l ;

if

( s r n t p s e r v e r == n u l l 1 I t o E r n a i l == r ~ u l l I I fromErnai1 == n u l l I I b o d y == n u l l ) { S y s t e m . ~ u pt r i n t l n ( " U s a g e : ja v a m a i l - s a v e -S < s e r v e r > -T < t o e m a i l > - F < f r o m > -9 < b o d y > " ) ; Systern.exit(1);

try

i
//
C o r ~ f i g u r a r 10s p a r a m e t r o s p r e d e t e r r n i n a d o s P r o p e r t i e s p r o p s = new P r o p e r t i e s ( ) ; p r o p s . p u t ( " m a i l . t r a n s p o r t . p r o t o c o l " , "srntp") ; props.put("mail.srntp.host", s m t p s e r v e r ) ; props.put("mail.smtp.port", " 2 5 " ) ;

//

C r e a r l a s e s i h n y c r e a r u n riuevo rnerlsaje d e c o r r e o S e s s i o n r n a i l S e s s i o n = Session.getInstance(props); M e s s a g e rnsg = new MimeMessage ( r n a i l S e s s i o n i ;

//

C o r ~ f i g u r a r 10s carnpos DE, PARA, FECHA y ASUNTO rnsg. s e t F r o m i n e w I n t e r n e t A d d r e s s ( f rornEmai1) ) ;

rnsg.setRecipients[MessageeRecip1er~tType.TO,
1r~ternetAddress.parse ( t o E m a i 1 )) ; m s g . s e t S e n t D a t e (new Date ( ) ) ; ms3.setSubject ("Test Mail") ;

//

Guardar

el

SERVIDOR a 1 q u e d e s e a r n o s

enviar

el

e-mail

rnsg.setHeader("X-Server", s m t p s e r v e r ) ; //
Crear e l cuerpo d e l rnsg. s e t T e x t ( b o d y ); rner~saje

//-[

G u a r d a r e l e - m a i l e n un a r c h i v o S t r i n g filename = Systern.currentTirneMi11is ( ) t " .e-mail"; F i l e O u t p u t S t r e a r n o u t F i l e = new FileOl~tputStrearn(fi1ename); rnsg.writeTo(outFile);

System.out .prir,tln("E-mail

ha?

been

caved:"

filename)

Al leerlo, nos damos cuenta de que ninglin elemento nos resulta familiar. Observe que hemos utilizado la posibilidad de situar informaci6n adicional en la cabecera para almacenar el servidor SMTP al que el usuario desea enviar el archivo. Puesto que vamos a enviarlo, tenernos que mantener el nombre del sewidor en alguna parte; el lugar rnis sencillo es la cabecera del rnensaje de correo con el campo S e r v l d o r . Despuis de crear el rnensaje, en lugar de entregarlo a la clase T r a n s p o r t para su envio, grabamos 10s contenidos en un archivo utilizando el mktodo w r i t e T o ( . . .) . Se crea un nombre de archivo relativamente exclusivo utilizando el reloj del sistema. Sin embargo, en un entorno multihilo no estaria garantizado que produjera un nlimero exclusivo ya que es viable que dos o mls hilos invoquen al rnismo tiempoelmCtodosystem. c u r r e n t T ~ m e M i l l (~) s . El archivo resultante es un sencillo archivo de texto que puede verse en cualquier editor de textos. Abralo

y disfrute dc lo que ha conseguido el API de JavaMail. En la cabecera, veri la inclusi6n de nuestro campo

Asi, despuis de haber grabado el mensaje en el disco, habri que cargarlo y enviarlo de nuevo, a travis del constructor de la c l a s e ~ i m e ~ e s s a g que e nos perrnite pasar una I n p u t s t r e a m a la fuente del mensaje. Podemos utilizarlo y tomar la I n p u t s t r e a m del archivo.

El siguiente ejemplo toma 10s archivos con la extensidn " .e - m a i l " . e intenta enviarlos a la clase T r a n s p o r t para su entrega. Este ejemplo toma un directorio como argument0 (utilice " . " para el directorio actual) y, en cada archivo con la extensi6n " e - m a i l " invoca el mCtodo s e n d M a i l ( . .) :

j a v a . util. : import j a v a . i o . ' ; impart j a v a x . m * i l . +; I m p o r t j a v a x . m a i 1 . i n t e r n e t . ";

Import

import ] a v a x . a c t i v a t i u n . + ;

public

class

j avarnail

sendAll

extends

Object

p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ I ) { i f ( a r g s . l e n q t h == 01 1 S y s t e r n . o u t . p r i n t l n ( " U s a g e : javarnail 1 else { new j a v a r n a i l s e n d A l l ( a r g s [ O ] ) ;

sendAll

<directory>"1 ;

i
\ public javarnail sendAll(String s p o o l D i r e c t o r y )1

processMailList(spo01Directriry);

I
p r i v a t e void processMailList(String spovlDirectory) 1 F i l e r o o t D i r = new F i l e ( s p o o l D i r e c t o r y ); S t r i n g l i s t O f F i l e [ ] = r o o t D i r . l i s t (new f i l e f i l t e r ( ) ) ; f o r ( i r i t x=O; x File thisFile

< 1istOfFile.length;
=

new

File (rootDir,

x++l { l i s t 0 f F i l e [x]) ;

p r i v a t e void sendMall(Fi1e filename) 1 S t r i r l q To = f i l e n a r n e . g e t N a r n e ( ) , From S t r i n g m a i l s e r v e r = ""; try

"",

Subject="";

t
/ / Sarqar e l archlvu
BufferedInputStream in
=

new

BufferedInputStrearn( )) ; new F i l e J n p u t S t r e a r n ( f i l e r ~ a r n e

//

Confiqurar l a s porpiedades Sesion y Servidor S e s s i o n mailSessior1 = S e s s i o n . g e t I n s t a n c e ( n e w P r o p e r t i e s ( ) ) ; rnsg


=

MirneMessage in.close ( ) ;

new MirneMessage ( m a i l S e s s i o r ~ , i n ) ;

//

E l m e r l s a j e ya e s t d d e n t r o , p r o c e s e m a i l s e r v e r = rnsq.getHeader ("X-Server",

la
",")

cabecera
;

personalizada

msg.rernoveHeader("X-Server");
//
Ahora n e c e s i t a r n o s e n t r e g a r l o = rnailSession.getProperties(); Properties props p r o p s . p u t ( " m a i l . smtp. hc.st", m a i l s e r v e r ) ;

/ / C o r l f i q u r e P a r a , De To = rnsq.getHeader("To", From = rnsg. g e t H e a d e r ( " F r o m " , Subject = msq.getSubject ( ) ; //


Eriviar e l merlsaje T r a n s p o r t . s e n d ( m s g );

"," )

; ;

"," )

Systern.out.println("Mai1Out: To=" + To

+
+

"; S u b j e c t = "

mailserver

+ "; From=" + From S u b j e c t i "; S e r v e r = " "; Size=" + f i l e n a m e . l e n g t h 0

+ " bytes");

Capitulo 13

catch[E;iception ) { System.out.printlr~("MailOutFail: T s ) = "


t
t

t To t ": S u b j e c t = " + S u b j e c t t ";

"; FrrJrn="
t

t Fr,:#rn "; S e r v e r = "

mailServer " bytes:"

+ e);

Size="

filename.length(!

I
c l j s c f i l ~ F i l t e ri m p l e m e n t s F i l e r ~ a r n e F i l t e r ( public f i l e F i l t e r ( 1 1 1 p u b l i c b o c l e a n accept(Fi1e d i r , S t r i n g n a m e ] i f [ r ~ a m e . i r t d e s O f(".e-mail") ! = - 1 ) i retiurn t r u e ;

I else
1

return

false;

El mktodo s e n d M a i l ( . . . ) toma un objeto Flle para el archivo que deseamos abrir y enviar. DespuCs d e crear un B u f f e r e d I n p u t S t r e a m para el archivo, crearemosMimeMessage para su entrega eventual. Basta con pasar el I n p u t s t r e a m Si algo no funciona, se genera una Exception. Si no, funcionari con normalidad. iRecuerda que pusimos 10s detalles del servidor SMTP en la cabecera? Seri necesario restaurarlo (a menos que quernmos mantenerlo fuera). N o hay motivo para que se quede en ese lugar ya que no es vilido fuera de esta clase. T o m a n ~ o s el servidor SMTP y configuramos la propiedad en la sesi6n. Tras ello, podenlos enviado a la clase T r a n s p o r t para su entrega.

L q salida d e esta clase puede verla a continuaci6n, donde se imprimiri un mensaje para todos 10s mensajes
enviados con i s i t o :

Recursos JavaMail
Hay muchos recursos que proporcionan m i s informaci6n en el API d e JavaMail; basta con buscar en cualquier buscador. A continuacion, le ofrecemos un par d e recursos muy conocidos:
3 API oficial de JavaMail: http://java.sun.com/products/javamail/.

Direcci6n URL en la que encontrarl documentacion y descargas oficiales.

JavaMail
U ;Guru: JavaMail: http://www.jguru.com/faq/home.jsp?topic=JavaMail.

Recurso excelente, moderado por John Zukowski que realiza un fantistico trabajo respondiendo a preguntas relacionadas con JavaMail.

Hemos terminado el recorrido por el API de JavaMail. Como podri apreciar, es muy impresionante y flexible en el acceso y rnanejo de mensajes. El API abstrae 10s detalles de irnplementacibn de 10s protocolos subyacentes para otorgar un acceso completo y sin obsticulos a 10s mensajes do correo. En 1971, Ray Tomlinson pus0 la maquinaria en funcionamiento enviando el primer correo electronic0 jarnis registrado. "Me envik mensajes de prueba a mi rnismo desde una miquina a otra", recuerda. Tambikn ariade que "Los rnensajes de prueba no eran dignos de mencibn ...".

Encontrara' ma's informaci6n sobre la historia del e-mail en el sitio http://www,pretext.corn/ mar98/features/story2.htrn. (Gracias a Rachel Michigan por haber encontrado este recurso).
Con rnis de 30 arios de madurez, es una de las aplicaciones mis utilizadas en Internet. Su poder de permanencia se debe a que, corno seres humanos, nos encanta comunicarnos e intercambiar mensajes, deseo que no ha muerto, ni siquiera despuks de 3 dkcadas. La siguiente ola de aplicaciones esti a punto de llegar con la plataforma J2ME y empieza a asentarse en el rnundo de la telefonia mbvil y PDA. N o pasari mucho tiempo antes de que 10s usuarios de telkfonos mbviles pidan acceder a su sistema de e-mail a travks de un navegador. Ahora podemos ofrecer esta soluci6n, de forrna ripida y fiable, a travks del API de JavaMail. En el siguiente capitulo, examinaremos un de 10s cambios mis significativos de la especificaci6n J2EE: la actualizaci6n de la especificacion Enterprise JavaBeans a la version 2.0.

Arquitectura y diseno EJB


En capitulos anteriores, hemos hablado sobre 10s API de Java que pueden utilizarse para construir aplicaciones de lado servidor. Algunos de Cstos API, como JDBC y JNDI, proporcionan acceso a servicios de bajo nivel que cualquier aplicaci6n puede utilizar. Otros API, como servlets y JSP, permiten la creacion de componentes que se ejecutan en un entorno estructurado (el contenedor) que proporciona servicios de alto nivel. Este capitulo presenta un API para un nuevo tipo de componente J2EE: Enterprise JavaBeans (EJB). Los componentes EJB estin diseiiados para encapsular logica de empresa y proteger a1 desarrollador de aplicaciones de tener que preocuparse por muchos temas de nivel de sistemas, incluido transacciones, ksepridad, reajustabilidad, concurrencia, gestion de recursos, persistencia, manejo de errores e independencia de entorno operativo. Los principales cambios realizados en la especificaci6n EJB 2.0 con respecto con la versi6n 1.1 son 10s siguientes:
L I

Se introduce un nuevo tip0 de EJB, el bean controlado por mensajes. Puede ejecutar operaciones asincronas a travCs del servicio de mensajes de Java, Java Messaging Service (JMS). y puede, por lo tanto, emitir consultas y actualizaciones a la base de datos extremadamente optimizadas.

o El contenedor registra ahora 10s cambios realizados sobre beans de entidad de forma muy precisa

La especificaci6n define un lenguaje estindar de consulta llamado EJB QL. Este lenguaje permite la realization de consultas especificas a la base de datos, con independencia de la naturaleza del almacin persistente subyacente. ya no necesitarin mantenerlas.

o El contenedor mantendri relaciones entre 10s beans de entidad, de modo que 10s desarrolladores
CI Una nueva interfaz, la interfaz local, ha sido introducida sobre las interfaces remota y bisica. Los

EJB que exponen interfaces locales pueden ser invocados sin la sobrecarga de copia de parimetros, a diferencia de las interfaces remotas.

Capitulo 14
Todas estas adiciones se analizarin en 10s pr6ximos capitulos dedicados a la tecnologia EJB. En este capitulo, haremos un anilisis general de las razones que impulsan el desarrollo de componentes EJB en aplicaciones y veremos la forma de crear un sencillo EJB. En concreto, analizaremos 10s siguientes puntos:

O Los servicios que proporciona un contenedor EJB y 10s mecanismos por 10s que son proporcionados O Las circunstancias en las que tiene sentido utilizar 10s componentes EJB en una aplicacion O C6mo es un componente EJB O Cdmo un programador cliente (que podria estar desarrollando componentes Web de lado servidor) visualiza y accede a un EJB
0

C6mo ve un desarrollador EJB un componente EJB y las reglas que debe seguir a la hora de crear componentes EJB

O C 6 m o utilizar de forma efectiva 10s EJB en una arquitectura Web


DespuCs de haber cubierto esta informaci6n, abordaremos el proceso de disefio de una arquitectura que utilice componentes EJB, para crear un ejemplo prictico que aplicaremos en capitulos posteriores del libro:

O Los capitulos 15, 16 y 19 analizarin detenidamente 10s tres principales tipos de componentes EJB: beans de sesi6n, beans de entidad y beans controlados por mensaje. Los beans de sesi6n y 10s beans de entidad tienen dos principales subtipos. Los beans de sesidn pueden ser con estado o sin estado; y 10s beans de entidad pueden tener persistencia controlada por bean o persistencia controlada por contenedor. Analizaremos las ventajas y 10s usos de diseiio de cada tip0 y subtipo de bean desarrollando versiones alternativas de sencillos componentes EJB. Ademis, continuaremos aplicando el ejemplo estudiado en este capitulo. O El Capitulo 17 analiza con detenimiento cuatro de 10s servicios que ofreceri un contenedor EJB: transacciones, seguridad, manejo de excepciones y comunicaci6n remota. Parte de este material es algo complicado per0 sera necesario que lo comprendamos para utilizar componentes EJB en un entorno real de gran volumen.
El Capitulo 18 examina 10s cornponentes EJB desde la perspectiva del proceso de desarrollo. Examinaremos 10s roles e~~licitamente definidos en la especificaci6n EJB, y las actividades necesarias para cada rol. Asimismo, ampliaremos la aplicaci6n de muestra desarrollada desde el Capitulo 15 hasta el Capitulo 17 para incluir una interfaz web. Esto nos permite estudiar como debemos configurar nuestro entorno para una aplicacidn que cuente con componentes web y componentes EJB. Comenzaremos por la definici6n exacta de EJB. TambiCn veremos brevemente algunas de las finalidades de 10s EJB.

i Q u e son los EJB?


Un EJB es simplemente una colecci6n de clases Java y un archivo XML, integrados en una irnica unidad. Las clases Java siguen ciertas reglas y proporcionan mktodos especificos de retrollamada, tal y como esti definido por el entorno de contenedor JZEE y las especificaciones EJB.
U n EJB ejecuta un contendor EJB. El contenedor EJB se ejecuta en un servidor de aplicaci6n y se responsabiliza de 10s temas de nivel de sistema. Esta divisi6n de tareas entre el desarrollador de EJB y el

720

Arquitectura y disefio J B
contenedor ue permite a1 desarrollador centrarse en la 16gica de empresa en vez de en la programaci6n j.q de nivel de slstema, es una parte impor:ante del pensamiento que subyace a la tecnologia Enterprise JavaBeans. Los EJB son tecnologia Java por lo que no deberia sorprendernos que no e s t h ligados a ningun sistema operativo concreto. Por ejem~lo, ~ o d e m o escribir s un EJB en Windows 2000 y desplegarlo en Linux, Solaris o incluso en AS/4000. La importancia de esto se vuelve aparente cuando consideramos que la unica tecnologia comparable (disponible en la actualidad) para el modelo EJB, NET (COM) de Microsoft, se ejecuta exclusivamente en plataformas de Microsoft. (Puede encontrar una comparaci6n entre C O M y EJB en http://java.sun.com/products(ejb/ejbvscom,html.)

El Modelo de Componente C O R B A es esencklmente un supergrupo multi-lenguaje de la especifi:cacio'n Enterprise JavaBeans. En su momento, estos componentes de lenguaje neutro quiza3 desempe~en un papel importante en muchas arquitecturas de aplicacio'n. Existen diversas implementaciones del Modelo de Componente C O R B A , algunas de ellas de co'digo abierto. Puede encontrar punteros de estas implementaciones en http:/lditec.um.es/-dsevilla/ccm/.
La intenci6n de la especificaci6n EJB es proporcionar una definici6n de c6mo deben interactuar 10s componentes de lado servidor, de mod0 que 10s desarrolladores puedan elegir entre diferentes vendedores -. \ y cambiar ficilmente entre ellos. En muchos aspectos, la especificacion alcanza su objetivo per0 existen todavia ciertos puntos de 10s que nosotros, como desarrolladores, debemos ser conscientes de modo que 10s EJB que creemos sigan siendo tan neutros respecto del vendedor como sea posible. Los EJB son simplemente una especificaci6n para una arquitectura de componentes de lado servidor (dentro del entorno de J2EE) que cualquier compahia puede implementar. Si un EJB no aprovecha ninguna de las extensiones de propiedad de una determinada implementaci6n, puede ser trasladado de una implementaci6n a otra a medida que vayan cambiando 10s requisitos de la apkaci6n. El EJB podria desarrollarse en un servidor de cddigo abierto y de bajo coste per0 podria desplegarse en un contenedor de alta finalidad que tenga funciones (como equilibrio de carga y relevo) que proporcionan un alto grado de fiabilidad. Los EJB son componentes reutilizables. El desarrollo basado en componentes ha demostrado su valia en el desarrollo de aplicaciones de cliente (por ejemplo, nadie se plantearia disehar una G U I sin utilizar componentes preconstruidos). U n EJB pretende ser un lote reutilizable de 16gica de empresa. Incluso aunque 10s EJB no se vendan para su reutilizacidn fuera de una compahia, seria posible reutilizar la 16gica de empresa en diferentes contextos dentro de una misma compahia. Los EJB pueden funcionar con cualquier tip0 de cliente. situaciones en las que pueden emplearse 10s EJB:
0

st? es una enumeraci6n (nada exhaustiva) de las

Los EJB pueden ser utilizados en conjunci6n con servlets y piginas JSP para proporcionar acceso a clientes Web.

0 Se puede acceder directamente a 10s EJB desde clientes Java que utilicen M I .
0

Se puede utilizar CORBA par acceder a 10s EJB de un servidor que soporta M I / I I O P .

0 Se puede utilizar XML a travks de un servlet para proporcionar acceso a cualquier tip0 de cliente que se a d a ~ t a e XML. Esta idea ha sido ~resentada recientemente al World Wide Web Consortium v se ha convertido en una especificaci6n independiente con el nombre Simple Object Access Protocol (SOAP). Puede encontrar mis informaci6n sobre SOAP en http://www.w3.orgTWSOAP/.

Los EJB tienen muchas ventajas. Pueden estimular la productividad del desarrollador, pueden ayudar a estructurar el modelo subyacente al sitio Web interactivo de su empresa; e incluso pueden llegar a convertirse en la mayor aplicaci6n de comercio electr6nico. Antes de seguir adelante, es importante aclarar una foco comun de confusion para desarrolladores no familiarizados con 10s EJB: c6mo 10s EJB estin relacionados con JavaBeans.

Enterprise JavaBeans versus JavaBeans


Enterprise JavaBeans quizis no fue una eleccidn de nornbre muy afortunada porque el API EJB ( t a m b i h conocido como arquitectura de cornponentes) tiene muy poco en cornfin con la arquitectura de componentes de nombre similar, JavaBeans. JavaBeans y Enterprise JavaBeans tienen objetivos, implementaci6n y uso muy diferentes. La arquitectura JavaBeans e s t i disefiada para proporcionar u n formato para componentes de fines generales, mientras que la arquitectura de Enterprise JavaBeans proporciona u n formato para componentes de 16gica de empresa altamente especializados desplegados en u n entorno J2EE. Los componentes E.JB, 10s cornponentes de servlet y 10s cornponentes JSP tienen rnis factores en comfin que cualquiera de ellos con JavaBeans. La siguiente tabla le ayudari a cornprender c6mo se relaciona la ticnologla EJB con otros componentes ~ a v a : Componente Objetivo del componente Nivel de ejecuci6n Servicios habituales provistos por el entorno de ejecuci6n de periodo de eiecucion Bibliotecas Java. Otros servicios varian si nificativamente con el conteneior t o r ejempIo, docurnento e Microsoft Word, aplicacion Java). Servicios de ciclo devida, servicios de red, decodificacibnde solicitud, formateado de respuesta.

JavaBeans

Arquitectura de componentes de objetivo general

Cualquiera

Servlets

Implementa un paradigma solicitud-respuesta, especialmente para protocolos Web Provee la generacion de contenido dinirnico, especialmente para entornos Web Provee la encapsulaci6n y gesti6n de logica de empresa

Servidor (especificarnente el nivel Web)

JavaServer Pages

Servidor (especificarnente la capa Web) Servidor especificamente a capa de 16gica de empresa)

Todos 10s servicios de servlet, directivas, extensiones de etiqueta, alrnacenarniento en bufer de respuesta. Persistencia, transacciones declarativasy seguridad,agrupaci6n de conexiones, servicios de ciclo de vida, apoyo para servicios de mensajes.

Enterprise JavaBeans

Variedades de beans
El objetivo principal de la tecnologia EJB es proporcionar una arquitectura de cornponentes estindar para la creacion y uso de sistemas de empresa distribuidos orientados a objetos. Este ambicioso objetivo no se podria alcanzar con solo un modelo para un componente, por lo que la especificaci6n EJB 2.0 ofrece tres modelos para metodos de retrollamada y ciclos de vida de periodo de ejecuci6n. Los tres tipos de EJB que implementan estos rnodelos son beans de entidad, beans de sesi6n y beans controlados por mensaje. Las diferencias entre estos tres tipos de EJB son cornplejas. Un bean de sesi6n esti destinado a ser utilizado por un unico cliente a la vez, por lo que se puede considerar una extension del cliente en el servidor. Puede

Arquitectura y diseiio EJB


proporcionar 16gica de empresa, como calculos del indice de devoluci6n para una inversi6n o puede ahorrar estado, como un carro de la compra para un cliente Web. La vida de un bean de sesi6n no se corresponde con la de su cliente. Cuando el cliente abandona el sitio Web o cierra la aplicaci6n, el bean de sesi6n tiene libertad para desaparecer. Ya no esti disponible para su acceso por otros clientes. Piense en un bean de entidad como en una representaci6n de datos orientados hacia el objeto en una base de datos. Al igual que una base de datos, mdtiples clientes pueden acceder simultineamente. U n bean de entidad podria representar un comprador, un product0 o una cuenta. La vida de un EJB de entidad es tan larga como la de 10s datos que representa en la base de datos. Cada uno de estos tipos de EJB tiene dos importantes sub-tipos. U n bean de sesi6n puede ser con estado o sin estado. U n bean con estado puede mantener informaci6n en nombre de su cliente en llamadas de mktodo (como un bean de carry de la compra). U n bean sin estado no puede ni lo necesitaria, (por ejemplo un bean calculadora). Es una importante distincion y, en la prictica, 10s EJB con sesi6n y sin sesi6n se utilizan para diferentes prop6sitos. U n bean de entidad puede tener su relaci6n con 10s datos en la base de datos gestionada por el programador (persistencia gestionada por bean) o por el contenedor (persistencia gestionada por contenedor). Esta distinci6n seri importante a menudo desde la perspectiva de la productividad o del rendimiento. Sin embargo, puede utilizar ambos tipos de bean de forma intercambiable en su disefio. U n EJB controlado por mensaje es invocado asincronicamente y puede recibir e influir sobre mensajes JMS a travks del proveedor de Servicio de Mensajes Java (JSM). Normalmente, un cliente enviari un mensaje a una Cola o Destino JSM especifico y todos 10s EJB controlados por mensaje que estin suscritos a este destino recibirin este mensaje. <Entrecuantos tipos diferentes de beans debemos decidir? La respuesta depende del punto de vista de la pregunta:
0 Desde el punto de vista de 10s mktodos de retrollamada y las interfaces de base que deben implementar 10s EJB, hay tres: beans de sesibn, beans de entidad y beans controlados por mensaje. 0 Desde el punto de vista de su arquitectura, hay cuatro: beans de sesi6n con estado, beans de sesi6n sin estado, beans de entidad y beans controlados por mensaje. 0 Desde el punto de vista de su implementaci6n, hay cinco: beans de sesi6n con estado, beans de sesi6n sin estado, beans de entidad con persistencia gestionada por contenedor, beans de entidad con persistencia gestionada por bean y beans controlados por mensaje.

Cuando hayamos concluido 10s capitulos sobre EJB, comprenderemos en su totalidad todos 10s temas y concesiones relacionadas con cada tip0 de EJB.

lPor que utilizar EJB?


El disefio de una aplicaci6n Java de lado servidor debe tener en cuenta c6mo funcionan conjuntamente servlets, piginas JSP y Enterprise JavaBeans y cuiles de ellos son apropiados en diferentes circunstancias. Muchos sitios Web han demostrado que es posible proporcionar contenido dinimico utilizando s610 senlets o piginas JSP, por lo que podria parecer que este nuevo API afiade complejidad innecesaria al proceso de desarrollo. La especificaci6n EJB pretende proporcionar servicios de nivel de empresa. Es decir, proporcionar funcionalidad que resulta fundamental para el prop6sito de una organizaci611, independientemente de la escala. Consecuentemente, la especificaci6n EJB es algo compleja en su modelo de administraci6n y programaci6n. Del mismo mod0 que un sencillo sitio Web sin requisitos dinimicos deberia ser escrito en HTML, una aplicaci6n con s61o modestos requisitos de bgica de empresa es mejor servida evitando la complejidad de 10s EJB. Debe utilizar un servlet y una implementaci6n JSP (utilizando JavaBeans para la 16gica de empresa y el acceso de datos).

El API de EJB permite a 10s desarrolladores evitar 10s semicios de programaci6n de nivel de sistemas, dejindoles libertad para centrarse en la 16gica de empresa. U n sitio Web que solo necesita proporcionar a sus usuarios contenido dinimico probablemente no requiere, en primer lugar, esos semicios de nivel de sistemas per0 muchas aplicaciones si requieren esos semicios y la tecnologia EJB cubre esta necesidad. La documentaci6n de Sun para la plataforma Java 2 Enterprise Edition incluye una publicaci6n que analiza como encajan las diversas tecnologias J2EE. Este documento, Designing Enterprise Applications with the Java 2 Platform, Enterprise Edition (tambikn conocido como J2EE Blueprints) esti disponible en http:// java.sun.com/j2ee/blueprintsl y cataloga cuatro arquitecturas para aplicaciones Web:

o H T M L bisico
0 0

H T M L con piginas JSP y semlets Semlets y piginas JSP que acceden a componentes JavaBeans modulares

O Semlets, piginas JSP, componentes JavaBeans y Enterprise JavaBeans


Estas arquitecturas son cada vez mis complejas per0 tambien mas solidas. Como ya hemos visto, resulta sencillo escribir una pigina JSP o un semlet que ofrece contenido dinamico. T a m b i h es posible integrar acceso a directivas y datos dinamicos en la logica de presentacion para habilitar el ripido desarrollo de la aplicacion. Sin embargo, seria dificil ampliar y mantener el codigo resultante. Adicionalmente, seria dificil separar las funciones de disefiador Web y desarrolladores de la logica de empresa. Cualquier aplicaci6n compleja se beneficiaria de un enfoque modular. Hemos visto c6mo pueden utilizarse JavaBeans con piginas JSP para separar el procesamiento de datos de la bgica de presentacion, proporcionando una mayor facilidad de mantenimiento y reutilizaci6n de codigo. Aunque puede que precise trabajo adicional, siempre seri mejor para la inversion cualquier aplicaci6n Web menos sencilla. En cierto sentido, afiadir tecnologia EJB simplemente amplia un nivel esta Modularidad. A medida que aumentan en complejidad 10s requisitos de una aplicacion, el acceso a la logica de empresa y 10s datos persistentes se traslada a la componentes EJB. Sin embargo, la decision de utilizar EJB no deberia basarse solamente en la complejidad de la aplicaci6n. La tecnologia EJB tambien resulta apropiada cuando se requieren 10s semicios proporcionados por un contenedor EJB. Las ventajas habituales proporcionadas por un contenedor EJB, y a menudo denominadas semicios de nivel de sistema, incluyen transacciones, reajustabilidad, persistencia, sepridad, posibilidades futuras de crecimiento, acceso remoto, reservas, recursos estrictamente controlados y acceso desde otros tipos de clientes. Recuerde que 10s EJB conllevan algunas concesiones y no se obtienen las ventajas anteriores sin un coste. Una aplicacion tiene cierta cantidad de sobrecarga dependiendo de la frecuencia y el tamaiio de las llamadas de red que realiza, y se consumiri mis memoria cuando estC presente el semidor de aplicacion. El mejor mod0 de decidir si 10s EJB son o no apropiados es considerandolos objetos de empresa de una aplicacion. Son representaciones orientadas hacia el objeto de reglas de empresa: lo que posee una organizacion, lo que debe, como opera, quien trabaja en ella, quiin puede obtener beneficios, quC se vende, cuinto se cobra, etc. Si una aplicaci6n necesita acceder a estas reglas, debe hacerlo a travCs de la representation de objeto de empresa. Sin embargo, si la aplicacion necesita capturar la complejidad de un proceso; si necesita leer, validar, transformar y escribir datos en unidades consistentes; si necesita mantenerse segura o si necesita ser reutilizada en diferentes contextos, entonces tiene sentido aprovechar 10s semicios que puede ofrecer un contenedor EJB. La especificacion EJB esti disefiada para representar objetos de empresa sin que el programador de 16gica de empresa tenga que proporcionar semicios de nivel de sistema. Por lo tanto, la tecnologia EJB no es adecuada para ser utilizada como un sistema de informacion, para procesamiento analitico o para semir archivos a la Web. Pero si una aplicacion necesita acceder a 16gica de empresa de cualquier complejidad, la escritura de 16gica de empresa como componentes EJB abrira nuevas posibilidades en la productividad de 10s desarrolladores, en el despliegue de la aplicacion, en el rendimiento, en la fiabilidad y en la posibilidad de reutilizacion de codigo.

Arquitectura y diseiio EJB

El contenedor EJB y sus servicios


Un contenedor es un entorno de ejecucion para un componente. El componente vive en el contenedor y el contenedor proporciona servicios para el componente. De modo similar, un contenedor a menudo vive en una sewidor de aplicacion, que proporciona un entorno de ejecuci6n para 61 y para otros contenedores:

Contenedor

Contenedor

Tecnicamente, un componente interactua solo con su contenedor y con 10s recursos que proporciona. Sin embargo, como la interfaz entre el contenedor y un servidor de aplicacidn n o esti bien definida, un unico vendedor proporcionari 10s dos, por lo que la distinci6n seri a menudo insignificante. Si un API entre un contenedor y un servidor de aplicacion se normaliza, la distincion seri m i s importante. U n componente EJB se escribe normalmente para aprovechar 10s servicios que proporciona el contenedor (es decir, el entorno de ejecucih). Comprender cuiles son estos servicios nos ayudari a comprender cuindo resulta apropiado utilizar componentes EJB en el disefio de aplicaciones y quC papel deben desempefiar. Examinemos algunos de 10s servicios que debe ofrecer un contenedor EJB.

Persistencia
Si asi lo decidimos, podemos leery escribir en una base de datos utilizando directamente el API JDBC. Esto puede resultar apropiado si simplemente necesitamos leer algunos datos para generar una pigina Web dinimica o para actualizar alguna information sencilla. Si tenemos necesidades complejas, 10s EJB proporcionan servicios de persistencia. Estos servicios comprenden desde sencillas reservas de conexiones hasta la gestion automitica de la persistencia y evitar que el desarrollador de la aplicacion tenga que escribir cddigo SQL. Escribir codigo de acceso a datos se presta a errores y precisa de tiempo a menos que se utilice una herramienta (como un sistema de asociacidn objeto/relacional). La especificacih EJB reconoce este hecho cuando hace referencia a EJB que n o aprovechan la persistencia automitica:

"Esperamos que la mayor parte de beans de empresa sean creados por hewamientas de desawollo de aplicaciones que encapsulard'n en componentes el acceso n datos".
Considere algunos de 10s puntos implicados si creiramos el cddigo de acceso a datos para una aplicacion:
0 0

t C 6 m o generamos actualizaciones para bases de datos optimizadas para 10s datos que han cambiado? t C o m o comprobamos suficientemente las actualizaciones generadas dinimicamente?

Capitulo 1 4
iC6rno controlarnos una situacibn en la que cornplicados grificos de objetos deben sincronizarse con la base de datos? iC6rno rnanejarnos las asociaciones de tipos de datos a diferentes bases de datos? iC6rno asociarnos relaciones entre objetos Java a relaciones entre tablas de bases de datos? <C6rnornantenernos la consistencia de la representaci6n persistente, cuando las actualizaciones pueden proceder no s610 de otros servidores J2EE de un cluster sino tarnbiin de servidores distintos a J2EE que acceden a la base de datos e incluso de procesos distintos de Java? (Corno dato curioso, esta situacibn se rnaneja norrnalrnente a travis de una tkcnica denorninada aceptacibn en dos fases e irnplernentada por un protocolo llarnado XA.) Ninguna de estas tareas es irnposible y ni siquiera dificil para un prograrnador cualificado; per0 quizis no aiiadan valor alguno a su product0 y sencillarnente puede resultar un coste innecesario. Los servicios de persistencia proporcionados por un entorno de ejecucibn EJB pueden rnarcar la diferencia entre el ixito o el fracas0 de un proyecto real con restricciones de tiempo, presupuesto y personal.

Transacciones declarativas
Es cierto que el API JDBC proporciona funcionalidad para gestionar una transacci6n, por lo que esto posiblernente podria realizarse desde un sewidor o desde una pigina JSP. Sin embargo, la gesti6n de transacciones puede ser cornpleja, particularrnente si intervienen multiples cornponentes de acceso a datos o multiples fuentes de datos. Por otro lado, las transacciones cornplejas con EJB pueden ser gestionadas sin ningun cbdigo. El API Java relacionado con la gestibn de transacciones, Java Transaction API (JTA) proporciona una interfaz estindar entre un gestor de transacciones, un servidor de aplicacibn, un gestor de recursos y una aplicaci6n o un cornponente de aplicaci6n, per0 casi ninguno de estos API esti destinado a ser utilizado por programadores de aplicaciones. U n segundo API relacionado con la gesti6n de transacciones, Java Transaction Service (JTS), es incluso menos probable que sea directamente util para un prograrnador de aplicaciones. Esta especificacibn esti destinada a vendedores que necesitan asociar una irnplernentacibn JTA a la especificacibn CORBA Object Transaction Service 1.1. Ahora que somos conscientes de estos API, podemos olvidarnos de ellos.

Seguridad declarativa
En una aplicacibn real, el acceso a datos y la funcionalidad de Ibgica de ernpresa deben ser seguros. Es posible que el desarrollador proporcione seguridad utilizando sewlets o piginas JSP per0 Csta es una tarea compleja y proclive a errores. Si multiples servlets o piginas JSP utilizan clases con 16gica de empresa com6n, seria necesario que una aplicacibn proporcionara un sisterna de seguridad personalizado. Afortunadamente, el acceso a componentes EJB puede ser regulado sin cbdigo.

El modelo de seguridad EJB ha sido criticado por su simplicidad. Por ejemplo, es incapaz de especijicar seguridad basada en instancias de EJB ( s d o clases). Por este motivo, 10s desarrolladores EJB tienden a confiar en la seguridad proporcionada en el nivel Web, que es un enfoque maduro y comprobado.

Manejo de errores
Pocas aplicaciones serin efectivas sin un claro y consistente sisterna de manejo de errores. La especificacibn EJB define claramente c6mo 10s errores afectan a las transacciones, 10s resultados de cliente, el registro del servidor y la recuperacibn de componentes.

Arquitectura y disefio EJB

Sistema de componentes para Iogica de empresa


El desarrollo de software que representa una Iogica compleja de empresa requiere una amplia inversion en recursos de empresa. Entendiendo este hecho, 10s desarrolladores de software han estado persiguiendo durante decadas el objetivo de la reutilizaci6n de software. Los EJB son componentes de lado servidor que puede ser utilizados de forma simultinea por diferentes clientes. Si la 16gica de empresa incorporada en su a p l i c a c i h requiere una gran inversi6n de desarrollo, esta es la forma ideal de permitir respuestas miximas.

Reajustabilidad
La especificaci6n EJB requiere que el desarrollador de la aplicaci6n siga ciertas reglas en la codificacion de componentes de 16gica de empresa. Estas reglas estin disehadas para permitir a 10s servidores de aplicacion gestionar grandes cantidades de clientes simultineos, todos ellos realizando demandas significativas sobre componentes de Iogica de empresa y componentes de acceso a datos. Los componentes tambikn estin disehados para ser ejecutados en mfiltiples Equipos Virtuales Java y el servidor de la aplicacidn e s t i capacitado para funcionar en un clfister (en mfiltiples equipos) y para recuperarse del fallo en cualquier nodo agrupado. Aunque 10s servidores Web pueden convertirse en reajustables, 10s contenedores Web no estin disefiados especificamente para reajustar componentes con cddigo 16gica de empresa y acceso a datos. El Capitulo 15 analiza cdmo muchos varios usuarios pueden compartir instancias de un EJB de sesi6n de servicio (conocido como reserva), conservando recursos del sistema. El cornponente equivalente de servicio en la grada web, un JavaBean, n o ser6 utilizado como reserva sin programacion personalizada. Ademis, el Capitulo 16 estudia como un contenedor EJB puede utilizar diversas estrategias para cachetizar datos de entidad. N o existe un mecanismo equivalente disponible para servlets o para piginas JSP.

Portabilidad
Aunque el desarrollo de la aplicaci6n puede proporcionar 10s mismos servicios que un contenedor EJB, cada uno de esos servicios debe ser desarrollado e integrado de forma indeuendiente. Si un entorno cambiante de empresa impone nuevos requisitos en una aplicaci6n, esos nuevos requisitos deben cumplirse con codigo personalizado (o tecnologia adquirida que debe ser integrada manualmente). Puesto que 10s EJB son escritos para un API estindar de industria, pueden a menudo ser ejecutados sin modificar en un nuevo servidor de aplicacion adaptado a J2EE.

Gestionabilidad
El problema fundamental con la gesti6n de componentes Web que contienen 16gica de empresa y ejecutan acceso a datos es que no son visibles para herramientas de gesti6n. Por ejemplo, considere el problema de controlar quikn puede cambiar la linea de credit0 de un comprador. Para asegurar esta funcionalidad con EJB, simplemente utiliza el control de acceso declarativo que proporciona el contenedor EJB para gestionar el acceso, ahadir o eliminar usuarios desde la funci6n apropiada. Para asegurar la aplicaci6n equivalente desarrollada de forma exclusiva con componentes Web, debe asegurar el acceso a todas las interfaces de usuario (es decir, vista Web) que proporcionan esta funcionalidad.

Como proporciona servicios el contenedor


Siempre ayuda tener una idea de 10s mecanismos por 10s que el contenedor EJB proporciona sus diversos servicios a componentes EJB:

Capitulo 14
O

Existen responsabilidades claramente definidas entre las diversas partes de una aplicaci6n que utiliza componentes Enterprise JavaBeans: el cliente, el contenedor EJB, el cornponente EJB y el gestor de persistencia. La definici6n de estas responsabilidades es conocida forrnalrnente somo contrato.

0 Los servicios que proporciona el contenedor estin definidos de tal forma que son ortogonales a1 componente. En otras palabras, seguridad, persistencia, transacciones y otros servicios estin separados de 10s archivos Java que implementan la 16gica de empresa del cornponente. 0 El contenedor se interpone en cada llamada a un componente EJB de modo que puede proporcionar sus servicios. Es decir, el contenedor se ubica entre el cliente y el cornponente en cada llamada de metodo de empresa.

Contratos
U n contrato es simplernente una instrucci6n de responsabilidades entre diferentes capas del software. Si cada capa software sigue las reglas de su respectivo contrato, puede funcionar de forrna efectiva con la capa superior y la capa inferior, sin saber nada rnis sobre esas capas. Esto significa que podemos combinar y unir capas sin rescribir nuestro cddigo siempre que nos atengamos a1 contrato y s61o a1 contrato. Hay tres capas perfectarnente definidas en la especificacidn EJB 2.0: cliente, bean y contenedor. Debido a 10s contratos entre estas capas, nuestro bean puede ejecutarse en diferentes contenedores, sin modificar. siernpre que exista una estricta adherencia a1 contrato por todas las partes, nuestro cliente puede acceder a diferentes beans, sin modificar:

Contenedor UB1 servidor de aplicacion

I I
I

Enterprise JavaBean

Por supuesto, 10s contratos son escritos teniendo en mente algo mis que la portabilidad. Estas reglas son cuidadosamente elaboradas para posibilitar que 10s vendedores de servidores construyan sus servidores en diferentes tecnologias, con diferentes capacidades. Podernos seguir estas reglas y patrones relativamente sencillos para aprovechar 10s servicios y capacidades de cualquier de estos servidores de aplicaci6n. i Q u e tipos de reglas existen? Las analizarernos detalladamente en posteriores capitulos, per0 estas son las principales:

Arquitectura y disefio U B
0

El desarrollador de un componente EJB (tambien conocido como "proveedor bean") debe irnplementar 10s metodos de empresa (cualquier metodo que proporcione acceso a la 16gica de la aplicaci6n) en la clase de implementacibn. Para 10s beans de entidad que utilicen Persistencia Gestionada por Contenedor (CMP), el proveedor de bean debe proporcionar definiciones para metodos abstractos que representan 10s campos C M P de 10s beans: (getName ( ) / s etName ( ) ,etc). El proveedor de bean debe definir las interfaces bisica y remota (o local) del bean para beans de sesidn y de entidad (esto no es necesario para beans controlados por mensaje). Para beans de sesi6n, el proveedor de bean debe implementar las retrollamadas de contenedor definidas enlainterfaz j a v a x . e jb. S e s s i o n B e a n .

0 Para beans de entidad, el proveedor bean debe implementar las retrollamadas de contenedor definidas enlainterfaz j a v a x . e j b. E n t i t y B e a n .
LI Para un bean controlado por mensajes, el proveedor bean debe implementar el metodo onbless a g e ( ) .

El proveedor bean no debe utilizar practicas de programaci6n que interferirian con la gesti6n de period0 de ejecucidn del contenedor de las instancias de bean de empresa. Por ejemplo, la especificaci6n prohibe explicitamente crear hilos en un EJB o acceder a1 sistema de archivos. Estas limitaciones hacen que 10s EJB sean mis portitiles ya que deben utilizar servicios provistos por en contenedor EJB para crear tal funcionalidad.

Servicios
El contenedor EJB proporciona servicios a1 programador de bean. Para la mayor parte, el programador de bean solo necesita seguir las reglas para beneficiarse de estos servicios. El desarrollador simplemente puede indicar al contenedor 10s detalles de lo que debe ser provisto. Esta funci6n se conoce como semintica declarativa y es una de las funciones mis 6tiles de 10s EJB. La informaci6n declarativa es especificada en un archivo XML conocido como descriptor de despliegue. Para muchas funciones, incluso esta informaci6n declarativa no resulta necesaria y el contenedor proporcionari la funci6n sin ninglin esfuerzo por parte del programador de bean. Uno de 10s servicios disponibles en cada senidor de aplicacion con un contenedor EJB es la gestion de transacciones. Las transacciones mantienen la consistencia de datos frente a conflictos o fallos de datos. El contenedor permitiri que un desarrollador de aplicaci6n indique (sin ninguna programacion) c6mo debe el cliente tratar 10s datos de empresa para asegurar la consistencia. Otro importante servicio proporcionado por 10s contenedores EJB es la persistencia automitica. Esta es una funci6n opcional para el desarrollador de bean per0 ofrece a muchos proyectos una valiosa alternativa a escribir miles de lineas de c6digo de acceso a datos. Los contenedores proporcionan mucho otros servicios, incluido:
0

Seguridad declarativa, que protege 10s recursos EJB de un acceso no autorizado. desde multiples usuarios y la transferencia de datos a mdtiples recursos.

LI Gestion de recursos (corno reserva de conexiones) y control de concurrencia, que facilita el acceso LI Manejo de errores, que facilita el aumento de la productividad del desarrollador de la aplicaci6n. O

Servicios de comunicacion, que facilitan el acceso remoto. El desarrollador de contenedor, n o el programador de la 16gica de empresa, implementa todos estos servicios. Esto es posible debido a que 10s componentes de 16gica de empresa (Enterprise JavaBeans) siguen el contrato definido en la especificaci6n.

Capitulo

1 4

Los contenedores pueden proporcionar servicios opcionales. Una irnportante opci6n para arnplios proyectos es la clusterizaci6n para relevo y reajustabilidad. Las herrarnientas de gestion no forrnan parte de la especificaci6n de EJB per0 son proporcionadas corno cornponente opcional por 10s vendedores de servidores y pueden ser irnportantes para el ixito o fracas0 de cualquier proyecto. Los posibles servicios opcionales s61o estin lirnitados por la irnaginaci6n del vendedor. A rnedida que 10s API Java se vayan expandiendo para envolver el rnundo, algunos de estos servicios adicionales probablernente se estandaricen. Tenernos un ejernplo en el API de Extensiones de Gesti6n de Java (JMX), que proporciona el rnenor denorninador cornlin para irnplernentaciones de gesti6n.

lnterposicion
U n desarrollador de aplicaci6n sigue las reglas del contrato de desarrollo de bean y entonces el contenedor puede proporcionar servicios de nivel de sisterna, pero, icorno es posible? Escribir un contenedor EJB de calidad es una tarea dificil per0 existe un concept0 central que facilita a1 desarrollador bean la cornprensi6n de lo que esti sucediendo, la interposici6n. Recordemos RMI. En RMI, el stub se interpone entre la interfaz de cliente y el objeto rernoto para proporcionar ernpaquetado y transporte de red. Del rnisrno rnodo, el contenedor EJB se interpone entre la interfaz de ernpresa de cliente y la logica de ernpresa EJB para proporcionar servicios corno transacciones, manejo de errores y gesti6n de persistencia. Una tipica llamada de metodo procedente de un cliente rernoto dirigida a un EJB funciona del siguiente modo:
0

El cliente realiza una llarnada en un stub RMI

0 El stub RMI se interpone en la llarnada del mitodo para leer (marshal) 10s parirnetros y enviar la informaci6n por la red

U n skeleton en el lado servidor decodifica (un-marshal) 10s parimetros y 10s entrega a1 contenedor EJB La llamada de mttodo todavia no ha alcanzado la 16gica de empresa ya que hay una segunda interposici6n. Algunos de 10s pasos siguientes pueden ser optirnizados, per0 la estructura 16gica es: El contenedor exarninari las credenciales de seguridad del que invoca ese metodo Empezari o se uniri a las transacciones requeridas Realizari las llamadas necesarias a funciones persistentes Desencadenari varias retrollamadas para permitir que el cornponente EJB adquiera recursos Invocari el mitodo actual de empresa Una vez invocado el mitodo, el contenedor realizari algunas funciones con transacciones, persistencia, retrollamadas, etc. Finalmente, 10s resultados del metodo de empresa, ya Sean datos devueltos o una excepcibn, serin enviados de vuelta a1 cliente remoto

Arquitectura y diseho I3 B

t
Stub RMI

A
Red

Stub RMI

Clase de ~nterpos~c~on generada por el I contenedor 1

Esto explica que la raz6n que subyace a una de las partes menos intuitivas de la tecnologia EJB. Los desarrolladores de aplicaciones pueden escribir una interfaz que declare las funciones de 16gica de empresa (representadas por el Stub RMI de la figura anterior) y escribir una clase que implemente esas funciones. Para obtener una imagen clara de la diferencia entre la interfaz Remota y la Bisica, piense en la interfaz Bisica como en una factoria; es el punto de entrada a un EJB y es la hnica entidad que puede sea alcanzada desde el exterior. Una vez hemos obtenido una instancia de la interfaz Bisica, le pedimos que Cree o localice EJB. Entonces se puede acceder a estos EJB a travks de su interfaz Remota. Sin embargo, no es precis0 que la clase implemente la interfaz. D e hecho, se recomienda a1 programador que no implemente esa interfaz en su clase de 16gica de empresa para evitar situaciones en las que se podria acceder directamente a la instancia de EJB en lugar de pasar por el proxy generado por el contenedor.

La nueva interfaz local de la especificacio'n 2.0 funciona del rnisrno rnodo que la interfaz rernota descrita except0 en que Psta no necesita utilizar 10s stubs y skeletons RMZ ya que la llarnada se realiza en la rnisrna V M .

Trabajar con EJB


La especificaci6n Enterprise JavaBeans esti escrita para diferentes phblicos per0 s610 nos interesan tres sectores:

Capitulo 14 .
o El desarrollador cliente
El desarrollador EJB (tambikn denominado "proveedor de bean")
0

El desarrollador de contenedor EJB

N o abordaremos 10s requisitos ticnicos de la especificaci6n desde el punto de vista del desarrollador del contenedor pero examinaremos de cerca aquellos aspectos que estin directamente relacionados con el programador de lado sewidor.

La vista del desarrollador cliente


U n cliente es cualquier usuario de un Enterprise JavaBean y podria ser una a p k a c i 6 n Java de lado cliente, una aplicaci6n CORBA, un sewlet o incluso otro EJB. U n programador de lado senidor que disefie una aplicaci6n Web o utilice un servlet para establecer la comunicaci6n con un EJB, necesita comprender c6mo se accede a 10s EJB y c6mo se utilizan. En proyectos de grandes dimensiones, es bastante probable que el programador Web y el programador EJB sean personas distintas. El programador cliente tiene menos preocupaciones que un desarrollador bean en cuanto a1 uso de EJB. Necesitan saber c6mo encontrar o crear un bean, c6mo utilizar sus m6todos y c6mo liberar sus recursos. U n cliente siempre utiliza el mismo procedimiento para la creaci6n de objetos, busquedas, invocaci6n de mitodos y eliminaci6n, independientemente de como se implements un EJB o de quC funci6n proporciona al cliente. El cliente no necesita preocuparse sobre la implementaci6n del EJB, las retrollamadas que realizari el contenedor EJB sobre el EJB o la naturaleza de 10s senicios provistos para el EJB. Los beans de sesion y de entidad tienen las siguientes interfaces:
O Una interfaz bisica, principalmente para operaciones de ciclo de vida como crear, encontrar y eliminar

EJB. La interfaz bisica no esti asociada a una instancia bean concreta, solo con un tip0 de bean.
U Una interfaz remota para metodos de empresa. Lbgicamente, representa la visi6n del cliente de una

instancia bean particular sobre el sewidor. La interfaz remota tambiCn proporciona algunos mitodos de infraestructura asociados a una instancia bean, en lugar de a un tip0 bean. Alternativamente, el bean puede utilizar una interfaz local, que es similar a la interfaz remota pero s d o resulta accesible para EJB de la misma unidad de despliegue. Es importante comprender que 10s beans de sesi6n y de entidad deben tener una interfaz bisica pero es optional si tienen una interfaz remota o una interfaz local (o ambas). U n programador cliente adquiriri una interfaz bisica a travis de JNDI. Esta interfaz bisica puede ser utilizada para:
0

Crear o encontrar una instancia de un bean, que se representari a1 cliente como interfaz remota Ejecutar mitodos de empresa en una instancia del bean

o Obtener una referencia serializable a1 bean, conocida como controlador


Eliminar el bean La eliminaci6n de un bean puede tener significados radicalmente diferentes dependiendo del tip0 de bean y es importante aclarar estas diferencias. En el caso de un bean de sesion con estado, significa que el desarrollador ha terminado de utilizarlo. El sewidor puede entonces liberar 10s recursos asociados a ese bean. En el caso del bean de sesi6n sin estado, tiene el mismo significado (aunque el sewidor probablemente no estaba consumiendo ningun recurso para el bean porque carecia de estado con el que comenzar). Puesto que las instancias de bean sin estado son resewadas, tambiin podria significar que la instancia en uso es devuelta a la resewa de bean de sesi6n disponibles. En el caso de un bean de entidad,

Arquitectura y diserio EJB


eliminar el bean significa eliminar su representacidn de vista de objeto en el almacen de datos persistentes (en otras palabras, borrarlo de la base de datos). Revisemos el proceso paso a paso. Utilizaremos un ejemplo de una aplicacidn cliente que quiere invocar un metodo p l a c e H o l d e r ( ) sobre un bean de sesion sin estado O r d e r M a n a g e m e n t . Este ejemplo pretende linicarnente ofrecer una idea de 10s tipos de clases que escribiremos y, como tal, su funcionalidad es bastante limitada. Sin embargo, para obtener experiencia prictica, implementaremos el bean en un servidor de aplicaci6n y ejecutaremos el cliente. Comience creando un directorio % BOOK-HOME% \ C h l 4 \ O r d e r M a n a g e m e n t \ en el que crearemos la aplicacibn. Exarninemos ahora 10s procedimientos relacionados con el desarrollo del cddigo cliente. Nuestras clases EJB estarin en un paquete o r d e r M g m t , por lo que necesitamos importarlo, asi como las otras clases que utiliza nuestro cliente:
import import import import orderMgmt.+; java.util.Prapertiss; j avax. naming. context; javax.naming.InitialCor~text;

A continuacidn, comenzamos la clase c l i e n t e:


public class Client { public static void main (String[] args) { try i

Primero, el cliente necesitari ser autentificado de algun modo especifico del servidor. Si el cliente es una aplicacidn Web, por ejemplo, la autentificacidn puede utilizar SSL. En segundo lugar, el cliente necesitari obtener I n i t i a l c o n t e x t adecuadamente inicializado como punto de partida para la bGsqueda J N D I . Si el cliente es un EJB ejecutado en un contenedor y el EJB a1 que pretende referenciar es declarado como recurso en el descriptor de despliegue XML, I n i t i a l c o n t e x t estari listo para su uso tan pronto corno sea instanciado. Si el cliente e s t i siendo ejecutado fuera d,e un contenedor, I n i t i a l c o n t e x t requeriri ciertas propiedades dependientes del servidor. Estas pueden ser proporcionadas en cddigo o utilizando un archivo de recurso. La inicializacidn del contexto sera especifica de su servidor de aplicaci6n o proveedor J N D I . para nuestro ejemplo, lo haremos programiticamente utilizando valores apropiados para WebLogic Server 6.1:
Properties prop = new Propertieso; prop.put(Context.INIT1AL CONTEXT FACTORY, "weblogic.j ndi . W L I n i t i a l C o r ~ t e x t F a c t o r y ") ; prop.put (Context.FROVIDER URL, "t3: //localhost :7001"1 ; Context ctx = rlew InitialContext (prop);

Ahora, encontremos la interfaz bisica para el bean O r d e r M a n a g e m e n t . El primer paso es buscarla utilizando el contexto inicial que acabamos de configurar. El nombre que utilizamos para buscar el bean depende del tip0 de cliente. Si el cliente es un EJB ejecutado en un contenedor y el EJB a1 que quisiera referenciar e s t i declarado corno recurso en el descriptor de implementacibn XML, entonces el nombre sera un sub-context0 del nombre j a v a : comp . / e n v / . Ademis, la especificacidn recomienda, pero n o requiere, que 10s nombres de EJB esten asociados al sub-context0 e j b:Por lo tanto, quizis busquemos la interfaz inicial del siguiente modo:
Object objref
=

ctx. lookup("java:c o m p / e r ~ v / e j b / O r d e r M a r ~ a g e m e r ~ t " ) ;

Desde la vista de un cliente ejecutado fuera de un contenedor, el bean puede asociarse a cualquier nornbre del espacio de nombre J N D I . Para nuestro cliente, buscamos la interfaz bisica del siguiente modo:
Object obj ref
=

ctx. l o o k u p ( " 0 r d e r M a r ~ a g e m e r ~ t; ")

Capitulo 14
El espacio de nornbre J N D I p u e d e incluir las interfaces bdsicas de EJB de mtiltiples servidores de aplicacidn ubicadas en cualquier lugar de una red. En general, el cliente no necesita saber la posicion de un EJB o la identidad de su servidor; sdlo necesita saber el nornbre a1 que esta asociado la interfaz bdsica del bean.
A continuation, necesitarnos ernitir esta referencia de interfaz bisica a la clase O r d e r M a n a g e m e n t . Esto no es tan sencillo corno una ernisi6n ordinaria de lenguaje Java. Para garantizar que el cliente funciona con cualquier protocolo de cornunicaci6n subyacente, la especificacion recornienda que el cliente utilice RMII I O P a traves del m e t o d o n a r r o w ( ) de j a v a x . r m i . P o r t a b l e R e m o t e O b j e c t . I I O P enconcreto n o se adapta a la ernision sencilla:
OrderM3rc3g?m?rctH.ime
(

horne = OrderMarlagementHorne) j a v a x . 1 - r n i . P e l - t a b l e R e m o t e O b j e c t . n a r r o w ( 'cbj r e f , OrderManagementHorne. c l a s s ) ;

Utilizarnos la interfaz bisica para crear una instancia de la clase O r d e r M a n a g e m e n t . Es irnportante cornprender que esta instancia es creada en el servidor. Todo lo que tenernos en el cliente es una referencia rernota a ella (es decir, el cliente tiene un stub). El c6digo es el siguiente:
OrderManagernerk arderMsrlagernerlt
=

horne. c r e a t e ( ) ;

Ahora podernos utilizar 10s metodos de ernpresa definidos en el bean O r d e r M a n a g e m e n t . En este caso, querernos invocar el rnetodo p l a c e o r d e r ( ) . Asurnarnos que torna tres parirnetros: nornbre de cornprador, nornbre de product0 o cantidad. El c6digo podria ser el siguiente:
' - ~ d e ~ M s n a g e m e .npt l a c e o r d e r ( " C e d r l c C ' ,

"J2EE S e r v e r P r a g r a m m l n g " ,

1000);

Finalrnente, podernos indicar el servidor que hernos terrninado de utilizar esta instancia del bean O r d e r M a n a g e m e n t . Podriarnos hacerlo utilizando la interfaz bisica de ciclo de vida pero, en realidad, es rnis conveniente invocar un rnktodo de utilidad r e m o v e ( ) definido en cada interfaz rernota EJB, asi:

o r d e r M a n a g e r n e n t . rerno.de i ) ; catch (Exception e ) { e.printStackTrace ( ) ;

El uso de la tecnologia Enterprise JavaBeans desde el cliente puede realrnente ser asi de ficil y escribir un cliente que utiliza la funcionalidad distribuida con EJB s610 resulta ligerarnente rnis dificil que escribir un cliente local. Guarde el c6digo para la clasecl i e n t en%BOOK-HOME% \ O r d e r M a n a g e m e n t \ C l i e n t j ava.Nopodernos cornpilar esta clase todavia porque no hernos creado el paquete orderMgrnt que contiene las clases EJB. El proveedor de bean crea estas clases y ahora buscarnos su vista en el EJB.

La vista del proveedor de bean


La principal responsabilidad del prograrnador de bean es escribir 16gica de empresa. Siernpre que sea posible,
la especificaci6n Enterprise JavaBeans intenta aliviar a 10s prograrnadores de bean de cualquier tarea de nivel de sisterna. A carnbio, el prograrnador de bean debe estructurar su c6digo de un rnodo deterrninado. N o irnporta el tip0 de EJB que este escribiendo el prograrnador (de sesi6n sin estado, de sesi6n con estado, controlado por rnensaje o de entidad). Habitualrnente, deben crearse tres archivos de clase Java prirnarios y un archivo XML. Dos de estos archivos Java son las interfaces analizadas en la secci6n

Arquitectura y diserio EJB


anterior: la interfaz bisica y la interfaz remota o local. El tercer archivo es la clase que contiene la verdadera 16gica de empresa, asi como algunos mitodos de retrollamada requeridos. Finalmente, el archivo XML, llamado descriptor de despliegue y nombrado ejb-jar.xm1, contiene informacidn estructural sobre el bean. Declara las dependencias externas del bean y especifica cierta informacidn sobre c6mo deben funcionar servicios tales como transacciones y seguridad. Tambiin puede haber clases Java adicionales que apoyen la operaci6n del bean; clases de ayuda que implementen 16gica de empresa Q, en el caso de un bean de entidad con una clave primaria compuesta, una clase que represente esa clave. Todos estos archivos estin empaquetados en un JAR (la unidad estindar de despliegue de Java que es, esencialmente, un archivo zip). Puede haber muchos beans en un dnico archivo JAR per0 cada archivo JAR contendri hicamente un archivo ejb-jar.xml. El descriptor de implementaci6n debe situarse en un directorio especifico (de mod0 que el contenedor EJB sabri donde buscarlo). Este directorio es METAI N F , todo en letras maydscdas.
U n punto comun de frustraci6n para desarrolladores principiantes de componentes EJB es ubicar su descriptor de implementacio'n en Meta - i n f o meta - i n f.

El resto de archivos se ubica en directorios apropiados a sus paquetes. Para el bean de ejemplo OrderManagement sobre el que estamos trabajando en este momento, la estructura de nuestro archivo JAR sera la siguiente:
META-INFI ejb-jar.xml orjerMgrnt\ O r d t r M a r l a q e r n e r ~ tc . lass 0rderManagerner~tHorne.cla-s OrderManagerr~er~tBear1 c .l a s s

Existen muchas formas de crear este archivo JAR, desde herramientas especializadas, hasta utilidades de archivo zip, pasando por la herramienta JAR estindar de JDK. Utilice el metodo que prefiera; el resultado seri el misrno. Crearemos el archivo JAR utilizando la herramienta de JDK. Tambiin habri informaci6n dependiente del servidor que necesita ser especificada cuando se implemente el bean. Por ejemplo, 10s nombres de recursos 16gicos y 10s roles de seguridad necesitarin asociarse a entidades reales en un entorno especifico de ejecuci6n. Los campos en beans de entidad que utilicen persistencia gestionada por contenedor quizis necesiten ser asociados a columnas especificas de tabla de base de datos. Variari la informacion adicional que precisa ser especificada pero la especificaci6n se escribe de forma que 10s EJB pueden ser desarrollados sin tener esto en cuenta.

C o n toda probabilidad, un desarrollador EJB trabajari desde un disefio que incluye la interfaz de 16gica de empresa que debe proporcionar. Esta interfaz es un buen punto de partida desde el que construir un Enterprise JavaBean. Los metodos de esa interfaz corresponderin probablemente a 10s mitodos de la interfaz remota EJB, con una diferencia: debido a la posibilidad de acceder a 10s EJB de forma remota, cada metodo de la interfaz remota (y la interfaz bisica) debe ser declarado para generar una excepci6n java . rmi RemoteException.puesto que~emote~xceptionesunaexcepci6ncornprobada, esto garantiza que el cliente tendri conocimiento de temas como el potencial de fallo de red.

La interfaz remota de un EJB debe ampliar la clase j avax .e jb . E JBOb ject,que amplia javax e jb. Remote. E JBOb j ect declara algunos mitodos comunes que se relacionan con cualquier instancia de un EJB:

package

javax.ejb;
(

public interface javax.ejb.EJBObject extends java.rmi.Remote E JBHome getE JBHome ( ) throws java.rmi.RemoteException;

Handle getHandle ( throws java.rmi.RemoteException; Object getPrimaryKey throws java.rmi.RemoteException; boolean isIdentica1 (EJBObject obj) throws java.rmi.RemoteException; void remove ( ) throws java.rmi.RemoteException, javax.ejb.RemoveException;

Para una interfaz local, la rinica diferencia estriba en que 10s me'todos n o lanzan R e m o t e E x c e p t i o n e n sufirrna y en queampkan E J B L o c a l O b j e c t en lugarde E J B O b j e c t .
El desarrollador EJB, en general, no necesita escribir cddigo para cumplir estos metodos: estin disponibles para el desarrollador cliente en cada bean que utilice. Algunos no tendrin sentido en ciertos contextos, en cuyo caso invocarlos tiene como resultado una excepcion. ~ s t es e un diagrama de clase de las relaciones entre las tres clases, que utiliza nuestra interfaz OrderManagement para la interfaz de empresa. Observe que la clase j ava . rmi .Remote es una interfaz de etiquetas sin metodos:

j a w rml Remote

jaw ejb EJBObject getEJBHome() getHandle() getPr~maryKey ~sldent~cal() remove()


1

orderMgmt OrderManagement placeorder() cancelorder() ~sSh~pped()

Continuemos con nuestro ejemplo de gestidn de pedido. Ya sabemos que existe un metodo placeorder ( ) y tambien desarrollaremos 10s metodos cancelorder ( ) y isshipped ( ) . Asumiremos el hecho irreal (pero sencillo de implementar) de que un comprador podria identificar un pedido indicando el product0 solicitado. La interfaz remota de EJB seria asi:
package orderMgrnt;

p u b l i c i n t e r f a c e OrderManagement e x t e n d s j a v a x . e j h.EJBOhject { v o i d p l a c e O r d e r ( S t r i n g c u s t N a m e , S t r i n g prodName, l n t q u a n t i t y )

Arquitectura y diseho EJB


throws
j a v a . r m i . Remot e E x c e p t i o r ~ ;

void car~celorde( r S t r i n g custName, S t r i n g t h r o w s java.rml.RemateException; b o o l e a r j 1 s S h i p p e d i S t r i r ~ gcustNarne, tk1r6w.q j a v a . r m i . R e r n o t e E x c e p t i o n ; Strirjg

prodName)

prodName)

I
Cree un directorio orderMgmt para albergar las clases en nuestro paquete orderMgmt y guarde el c6digo
como%BOOK~HOME%\0rderManagement\orderMg~\OrderManagement.~ava.

Observe que el desarrollador de aplicacion nunca implementa esta interfaz. Quizis se pregunte quiin la implementa; la respuesta es el contenedor EJB. Hay diversas formas en las que un contenedor puede implementar esta interfaz pero piense en el contenedor generando y compilando codigo Java en ultimo tirmino cuando implemente su bean. El c6digo que genera se encuentra donde el contenedor provee servicios como gestion de transacciones y seguridad. Este c6digo esti alli donde tiene lugar la interposicidn que hemos visto con anterioridad. Obviamente, el desarrollador de la aplicaci6n nunca implementa esta interfaz; debe proporcionar la logica de empresa en una clase de implementaci6n. Sin embargo, nunca necesitan escribir:

Ademis, se recomienda seriamente a 10s desarrolladores que lo hagan. ~ s t es e el privilegio del contenedor. La siguiente tarea en la escritura del bean de gestion de pedido es disefiar la interfaz bisica, que debe ampliarj avax . e jb .EJBHome. EJBHome tiene este aspecto:
package public javax.ejb; interface EJBHome extends java.rmi.Remote {

E JBMetaData getEJBMetaData ( ) throws java.rmi.RemoteException; HomeHandle getHomeHandle ( ) throws java.rmi.RemoteException; void remove (Handle handle) throws java.rmi.RemoteException, javax.ejb.RemoveException; remove (Object primaryKey) throws java.rmi.RemoteException, javax.ejb.RemoveException;

void

Estos mitodos estin disponibles para el programador de cliente, sin ningun esfuerzo adicional por parte del desarrollador EJB. El programador de bean escribiri una interfaz bisica, derivada de esta interfaz, que afiade uno o mis metodos dependiendo del tip0 de bean. U n bean de sesi6n con estado afiadiri uno o mis mitodos create ( ) . U n bean de entidad afiadiri ninguno o rnis mitodos create ( ) y uno o rnis mitodos finder ( ) . U n bean de sesidn sin estado, como nuestro bean de gestidn de pedido, debe definir exactamente un mitodo create ( ) (sin parimetros). Nuestra interfaz bisica de EJB OrderManagement,que debe guardarse como
%BOOK~HOME%\Ch14\0rderManagement\orderMgmt\OrderManagementHome.~ava,debetener

este aspecto:
package publlz orderMgrnt; lrlterface OrderMar~agerner~tHrrne extends

ja v a x . ejb.EJBHorne

Capitulo 14
OrderMar>agernent c r e a t e ( ) t h r o w s ja v a . r r n i . R e m o t e E x c e p t i o n ,

j avax . e j b . C r e a t e E x c e p t i o r ~ ;

La mayor parte del esfuerzo invertido en la escritura de un EJB ird a parar a1 desarrollo de la verdadera 16gica de ernpresa. Una clase, a rnenudo denominada clase "bean" o clase "implernentaci6n", es el punto central para el desarrollo de esta logica de ernpresa. Por supuesto, a1 igual que cualquier clase Java, esta clase bean puede diferenciarse en el procesamiento de otras clases ayudantes. La estructura especifica de la clase bean depende del tip0 de EJB. U n bean de entidad debe derivar de j a v a x . e j b . E n t i t y B e a n , u n b e a n d e s e s i h d e b e d e r i v a r d e j a v a x . e j b . SessionBeanyunbean controlado por rnensajes debe ampliar j a v a x . b e a n . e j b .MessageDriven. Laclase beandebe implementat las retrollarnadas definidas en su respectiva interfaz, aunque puede que estos mktodos de retrollarnada se queden a rnenudo en blanco.

La clase bean debe tener un metodo pliblico llarnado e j b c r e a t e ( ) (con argurnentos coincidentes) que se corresponde con cada metodo c r e a t e ( ) declarado en la interfaz bdsica. Puede crear tantas versiones sobrecargadas de e j b c r e a t e ( ) como necesite; solo aseglirese de que las hace corresponder con rnetodos e j b P o s t C r e a t e ( ) (que estardn vacios la mayor parte del tiernpo). Para un bean de sesion, el tip0 de retorno serd v o i d . Para un bean de entidad, el tipo de retorno serd la clase de la clave primaria. U n bean de entidad tambien irnplernenta un metodo e j b P o s t C r e a t e ( ) correspondiente. Para un bean de entidad con persistencia gestionada por bean, debe irnplernentarse metodos que se correspondan con 10s metodos buscadores declarados en la interfaz bisica de bean. Por el momento, rnientras vamos implementando un bean de sesion, utilizarernos las retrollamadas de bean de sesion.
Finalrnente, la clase bean debe tener metodos de logica de ernpresa que se correspondan con aquellos que hemos declarado en la interfaz remota del bean. La 16gica en estos metodos es el motivo por el que crearnos un EJB en primer lugar. La estructura de nuestra clase de bean de gesti6n de pedido podria ser ask
package import public orderMgrnt; javax. e jb. SessionCor~text; class void OrderManagernerltBean irnplernerlts
j avax. e j b. SessionBean
[

pliblic

Systern.out.println("0rder p l a c e d
1

p l a c e O r d e r ( S t r i n g custNarne, S t r i n g prodName, i n t q u a n t i t y ) [ f o r " + q u a n t i t y + " c o p i e s of " + prodName + " t o b e s h i p p e d t o " + c u s t N a r n e ) ;

p u b l i c v o i d c a r ~ c e l O r d e r ( S t r i n gc u s t N a r n e , S t r i n g Systern.out . p r i r ~ t l n ("Order cancelled") ; 1 p u b l i c b o o l e a n i s S h i p p e d ( S t r i n g custNarne, Systern.out . p r i n t l n ("Order s h i p p e d " ) ; return true; String

prodNarne)

prodNarne)

I
public void ejbCreate() [ called");

Systern.out.println("ejbCreate I )

I
p u b l i c v o i d ejbRernove0 [ Systern.out . p r i n t l r , ("ejbRemove() c a l l e d " ) ;
\

public

void

ejbActivate

( )

Arquitectura y disefio EIB


System.out . p r i n t l n ("ejbActivate( ) called") ;

I
public void ejbpassivate ( ) { System. o u t . p r i n t l n ( " e j b p a s s i v a t e ( ) called");

public void setSessionContext (SessionContext c t x ) { S y s t e m . o u t . p r i n t l n ( " s e t S e s s i o r ~ C o r ~ t e( x )t called") ;

I
Observe que, para este EJB de muestra, ninguno de 10s mktodos contiene ninguna 16gica de empresa. Sin embargo, 10s mktodos si producen mensajes para el usuario. Esto es asi de tal forma que podemos ver quk mktodos son invocados y cuindo. Guarde el c6digo como $BOOK~HOME\Ch14\OrderManagement\orderMgmt\OrderManagementBean.java. La linica parte de nuestro EJB que todavia no hemos analizado en el descriptor de implementation. Como esti escrito en formato XML, puede ser ficilmente leido y editado por programadores. En general, sin embargo, probablemente produciri este archivo utilizando una herramienta, quizis una que estk incorporada a su servidor de aplicaci6n o IDE. Como el descriptor de implementaci6n para este ejemplo es sencillo, lo crearemos manualmente. A continuacion, sin mis anilisis, presentamos el descriptor de implementaci6n XML, e j b- j a r .xml, para nuestro sencillo e j e m p l o ~ r d e r ~ a n a g e m e n t :
< ! DOCTYPE e j b - j a r PUBLIC ' - / / S u n M i c r o s y s t e m s , I n c . //DTD E n t e r p r i s e JavaBearts 2 . @//ENf ' h t t p : / / j a v a .sun.com/ j 2 e e / d t d s / e j b - j a r 2 O . d t d f >

Podemos desarrollar y probar este sencillo bean en el servidor de aplicaci6n de WebLogic para el que existe una copia con period0 de evaluaci6n de 30 dias disponible para su descarga en http://commerce .bea .corrcldownloaddweblogi~~setver.jsp. Durante la instalaci6n, se encontrari con una serie de opciones pero no puede simplemente aceptar 10s valores por defecto. Tambikn se le sugeriri que busque una contrasefia para ejecutar el servidor y un nombre de usuario y una contrasefia para iniciar la Consola (utilizada para gestionar WebLogic). Aseg6rese de que anota estos valores, ya que 10s necesitari mis tarde.

Una vez haya instalado WebLogic, debe cornprobar que estd funcionando. Inicie el Servidor WebLogic (si estd utilizando Windows 2000 el cornando habrd sido afiadido a menu Inicio). Introduzca su contrasefia cuando asi se solicite y, cuando se haya iniciado el servidor, abra su navegador y dirijase a http:// localohost:700Y. Si la instalacidn de WebLogic ha sido efectiva, veri algo ask

II
1

BEA WebLogic SewerTn1

b Visit the RE-A S?-steins. h r web site to learn rnore about how BEA WebLogic Server and the BEA WebLogic E-Business Platform provide you with the essential ltlfrastructure for butldmg an integrated e-business.

Use the Built on BEA logo on all your WebLogic Server applications For more mformation on becoming a BEA Partner, see Pal-hlel nth tlw Xlail.ret
L*:tllel

6 2001. BEA Systems, Inc. All &ts reserved.

& cite

r1 &fI

-1 local intranet
A

Si esta' utilizando un servidor distinto a WebLogic, tambie'n necesitara' realizar carnbios en el c6digo para este ejemplo. Necesitara' remitine a la docurnentaci6n de la aplicacidn para instrucciones sobre c6mo hacerlo.

En esta etapa, tenernos la siguiente estructura de directorio y archivo:


Ordert-lanagemert t \ Client . j a v a

ordorMgmt\

O r , i e rManaqement . j a ' l a O r , d e r M a n a q e m e r ~ t B e a rj~a. v a O r , J e r l 4 a n a q e m e r 1t H ' 3 m e . 3 a v a

META- IN F\

ejb-jar.xm1

T a m b i h necesitaremos un descriptor de despliegue adicional antes de poder irnplementar nuestro bean a WebLogic. El a r c h i v o w e b l o g i c - e j b- j ar . x m l contiene cualquier referencia a recursos externos, detalles de clusterizaci6n, etc., relevantes para el bean y es especifico de WebLogic. Para el caso de nuestro sencillo ejernplo, sin embargo, lo linico que contiene este descriptor es la inforrnaci6n que especifica el nombre J N D I de la clase inicial:

740

Arquitectura y diseiio EIB


< ! DOCTYPE

weblogic-ejb-jar PUBLIC '-//BEA System:, Inc.//DTD WebLogic 5 . 0 . 0 EJB//EN1 bed. c o m / s e r v e r s / ~ ~ ' 1 s 6 O O / ~ ~ t d / ~ . ~ ~ b l n qairc .de td jh 1,> ~ 'http://"ww.

Ahora estarnos preparados para cornpilar nuestras clases. Para cornpilar las clases EJB necesitarnos asegurarnos que incluirnos el paquete j a v a x . e j b en nuestra ruta de clase. Podemos hacerlo incluyendo %J2EE -~ 0 ~ ~ \ l i b \ j 2 j ea e r e.n l a r u t a d e c l a s e . Ejecute el siguiente comando desde el directorio %BOOK_HOME\Ch14\ O r d e r M a n a g e m e n t \ para crear las clases para nuestro EJB:

Tenen~os ahora 10s siguientes archivos y directorios que se empaquetarin en un archivo JAR:
O1-2rrManaqernent\

~:~r'jerMgmt\ O r d e r M a n a q e m e n t .c l a s s OL-derMar4aqementHome. c l a z s Or,jerManagemer~tBeanc . lass


META-INF\

eib-jar.xml w e h l i q i c - e j b- j a r . x m l

Para crear el archivo J A R ejecute el siguiente cornando desde el directorio %BOOK-HOME? \Chl4\ OrderManagement\:

DespuCs de haber desarrollado un cornponente, el siguiente paso es irnplernentarlo en el servidor de la aplicaci6n. Recorrerenios el proceso de implernentaci6n en WebLogic 6.1 que, con10 nuestro EJB es rnuy sencillo,'seri un proceso bastante ripido. Inicie el Servidor WebLogic y despues inicie la consola WebLogic; deberd introducir el nornbre de usuario y la contraseiia que introdujo durante la instalaci6n:

Capitulo 14
Una vez introducidos estos datos, veri la pigina inicial de la consola:

Welcome to t E A WebLoglc Server

Gettina Started

XML Remtnes JMS

WebLoglc Porna~nLqnt~ouranons Mach1nes

LkiIfi~

L1W

Tern~kags

Connsct~on

Security
Fealms

Connectivity WebLocl~c Enternrise I LKEC!Q Other Servlces

Copynghl (c) 6EA Syatems. lnc All nghls resarnd

Pulse U B en la secci6n Deployments y despues Install a new U B (Instalar un nuevo EIB). Despues, el b o t h Browse (Examinar) y seleccione el archivo OrderManagement jar que hernos creado:

Arquitectura y diserio D B

Instal or Update an Application

da?

, * ;bea

,-q

Upload and Install an Application C k k on the 'bfowSe' bmon b e l m to k a l e an appl~catlon archwe on your local hard dnve When you have located the 6 e . clrck 'upload to nstdl !ton Ihls WebLog c Adrn~nisVabon Sewer The foflovnngtypes ol app IceDon I i s may oe bp Gaaea A .Jarcontmng EJB5 (Enterprise Java Beans) A .war web Appkcahon Archw) conlalnlng JSPs and Servleh A .rar [Resrouce Adapter Archwe) contarnlng a JCA Conneclor module An .ear (J2EE Enlerprtse Appllcanon Archive) contmng any of the above Note 11 you browse for the file, you may h m lo adlust me hle-type f~lter to 'All' In order lo find jar, war, rar and earftles

Appllcatlon files currently installed:

Despuis haga clic en Upload (Cargar) para irnplementar el archivo JAR sobre WebLogic; veri una pantalla que confirrna la subida efectiva e instalaci6n de la aplicaci6n:

Install or Update an Application


Recmng f~l? ~~ploa hd5 d con-ql~leo, now I n s M n q d m e Upload and Install an Application

, . . d m ? ;.ha

Clkk on the 'btruwse' bmon below to locale an appl~cat~un arch~ve on your local hard drive When you have located m e hle, click 'upload' to install 11 on thls LWbLnglr. Admlnrstrdtlon Sewer The follornng r@es of applica~on f~les may be uploaded

. . .

A .jar contaming EJPs [Enterprise Java Beans) A .war (Web Appllcahon Archwe) cnntarnlnl J3Ps and SeMets A .rar (Resrouce Adapter Arch~vs) contalnlng a JCA Conn~ctor module An .ear (JZEE Enterpr~se Appbsat~on AR~IV*)conta~nmg amj uf rhe ahow

Note 11 you browse lor the f~le, you rnav have In adjusl the ble-me filler to 'AII' In order to f~nd pi, war, rarand earf~les

Application files currently installed:

Puede ver en la parte inferior de esta pigina que OrderManagement . j a r aparece enumerado como una aplicaci6n instalada. Ya estamos preparados para compilar y ejecutar nuestro programa cliente. Para compilar el cliente, ejecute elsiguienteco~nandodesde%BOOK-HOME'\Chl4\OrderManagement:

TambiCn necesitamos tener estns clases en nuestra ruta d e clase cuando ejecutemos el cliente. Para ejecutar el cliente, ejecute el siguiente comando:

Idealnzente, querrd tener u n archi.;o J A R dr cliente independiente que contenga s61o las clases necesarias: las interfaces ba'sica y rrrnota. Por ahora, sirrrplemente ariadinzos el archivo j a r del EJB que acabanros de irnplrrnentar para la ruta de clase.

Debe ver algo ask

Arquitectura y diset3o EJB

El progrnmn clicnte ha sido ejecutado con Pxito pero n o ha producido nada en pant~lla. En principio esto puede parecer extraiio, despuks d e habcr invocado el m e t o d o p l a c e ~ o l d e (r ) , que incluye el comnndo:

Entonces dcbernos esperar ver el resultatlo en pantalla que detnlle el pedidopresentado por el cliente. Sin cnibargo, el m6todo cs invocado sobre el EJB, que se ejecuta en el servidor, n o el cliente. Asi, el rn6todo 1 3 invitacidn de comnndo ejecutada en el p l a c e o r d e r ( ) ha sido ejecutado en el servidor. Si rnira~nos bervidor WebLogic, vemos que p l a c e o r d e r ( ) ha sido ejecutado con h i t o :

Tnmbien podemos ver que 10s mitodos s e t s e s s i o n c o n t e x t ( ) y e j b c r e a t e ( ) son invocados por el contenedor EJB. Sin embargo, e j bRemove ( ) n o parece haber sido invocado a pesar del heclio de que invocamos remove ( ) sobre la instancia del EJB en el programa cliente. Esto se debe a que el mornento de invocacidn de cste rnCtodo depende del contenedor EJB.

LQue no puede hacer un EJB?


Hemos hablado largo y tendido sobre las ventajas de prograrnacibn para la especificacidn EJB si e s t i desarrollando un sisterna transacciona!. C o m o desarrolhdores d e aplicaciones, se nos perdonan las rareas de programacion de nivcl de sistema. Esta es una gran ventaja para la productividad del prograrnador, la cnpacidad de la aplicacion y la fiabilidad del sistenla. N o obstante, para beneficiarnos realrnente, debemos acordar trabajar dentro del sistenia d e la tecnologia EJB y esto significa que hay ciertas cosas que n o poden~os h x e r sin perder cierto grado de portabilidad. En concreto, la especificacicin EJB 2.0 prohibe que 10s EJB realicen las siguientes funciones:

Capitulo 14
0 Utilizar la palabra clave s y n c h r o n i z e d y las primitivas de sincronizaci6n en general 0 Utilizar AWT u otras primitivas grificas 0 Pedir informaci6n de entrada desde el teclado 0 Utilizar el paquete j a v a i o 0 Realizar operaciones de red como aceptar o escuchar en un socket 0 Crear una c l a s e ~ l a s s ~ o a d e r

O Cargar una biblioteca nativa


Sin embargo, es poco probable que un programador de aplicaciones tropiece con estas restricciones. Otras tecnicas, mas comunes, de programaci6n tarnbien estin restringidas. U n tipico desarrollador de aplicaciones puede encontrarse con estas otras restricciones y querri saber el rnotivo de su imposici6n y c6mo puede conseguir su objetivo sin topar con ellas. En las siguientes secciones, exarninaremos algunas de estas restricciones.

API responsable de 10s hilos


N o podernos utilizar la palabra s y n c h r o n i z e d en ninguno de 10s mktodos de clase bean. La sincronizaci6n de 10s accesos puede desernbocar en un interbloqueo. (Podemos, sin embargo, utilizar clases de utilidad con rnktodos sincronizados, como v e c t o r . ) N o podernos iniciar, detener, suspender o reanudar un hilo. Seglin la especificaci6n, permitir a1 bean que gestione hilos rnermaria la capacidad del contenedor EJB para gestionar correctarnente el entorno del period0 de ejecuci6n. Algunas implernentaciones asocian contextos de transacci6n o seguridad al hilo; si el bean creara hilos adicionales, este mecanisrno podria no funcionar. Alternativamente, considere el caso en el que un proveedor de servicio de aplicaci6n desea albergar beans de rnliltiples clientes en algunas cajas Unix de gran tamaho. Este ASP necesita dirigir y controlar el uso de recursos de cada aplicaci6n, de rnodo que puede cubrir las garantias de calidad de servicios. U n o de estos recursos es el uso de hilos. Si a un bean se le permitiera crear hilos adicionales, seria rnis dificil de gestionar y controlar. Lo cierto es que deberia ser posible, quizis en alguna futura versi6n de la especificaci6n, proporcionar un API especial de hilo. Este API podria perrnitir a1 cornponente EJB recuperar hilos de una reserva de hilos gestionada por contenedor, sujeta a las lirnitaciones y gesti6n irnpuestas por el contenedor y el sisterna administrador. N o existen problemas tkcnicos fundamentales con este enfoque per0 el API especifico no existe en la actualidad en la especificaci6n EJB 2.0. En general, el desarrollador de la aplicaci6n puede confiar en que el contenedor gestione 10s hilos por kl de un mod0 eficiente. Normalrnente, existiri una reserva de hilos gestionados por el senidor. Cuando llega la solicitud de un cliente, uno de esos hilos de reserva sera asignado a1 procesamiento de la solicitud concreta. En la mayoria de 10s casos, no deberia ser necesaria una gesti6n explicita de 10s hilos y, en cualquier caso, es poco probable que sea posible.

iQue' sucede cuando la ldgica de empresa para una unica solicitud requiere procesamiento paralelo de varias rutas independientes para una operacio'n efectiva? Por ejernplo, digamos que antes de dewolver una respuesta de nuestro mitodo de empresa, necesitamos obtener informacidn de u n sistema ERP, un sistema de gestidn de ventas de legado y un sewidor Lotus Notes. Cada uno de estos sistemas tarda diez segundos en procesar una solicitud y ninguno de ellos depende de 10s datos procedentes del otro. Invocarlos en paralelo podria suponer unos diez segundos. Invocarlos en serie requeriria como minimo treinta. Por desgracia, no existe una respuesta satisfactoria para esta situacidn en la versio'n actual de la especificacidn.

Arquitectura y diserio U B

Los EJB no pueden utilizar el AWT para mostrar informacion o para introducir informacion desde un teclado. Es muy poco probable que un servidor de aplicaci6n permita una interacci6n directa entre su EJB y el teclado o el monitor. U n desarrollador de aplicaci6n que quisiera hacerlo deberia reconsiderar esta idea de la separacidn entre el G U I y las capas de 16gica de empresa.

Funcionar como un sewidor de red


Esto significa que n o podemos escuchar, aceptar o multidifundir en un socket. N o significa que n o podamos utilizar sockets en absoluto (un concept0 err6neo muy comGn);podemos utilizar un socket como cliente. Si el EJB funcionara como servidor de red, interferiria con la capacidad del contenedor para utilizarlo como componente de 16gica de empresa. Si necesitamos servir archivos, utilizamos un entorno apropiado, como un contenedor de servlet.

Escribir en campos estaticos


Esta restriccion es dificil de evitar para 10s programadores. Hay a1 menos dos problemas relacionados con la escritura en campos estiticos. Primero, necesitariamos protegerlos contra accesos concurrentes, que violarian la norma sobre sincronizaci6n de hilos. En segundo lugar, 10s campos estiticos solo son visibles en un JVM Java. Pero muchos contenedores utilizarian mdtiples equipos virtuales por motivos de rendimiento o fiabilidad y, en ocasiones, esos equipos virtuales se ubicarian en mdtiples equipos fisicos. N o existe un mecanismo para propagar la actualizaci6n de un campo estitico. Esto n o significa que n o podamos utilizar 10s campos estiticos: solo es necesario que Sean de solo lectura. Probablemente deberiamos declarar cualquier campo estitico como f i n a l para aplicar este requisito. En lugar de campos estiticos "escribibles", debemos utilizar un recurso compartido apropiado, como una base de datos.

El paquete java.io
Laespecificacion establece lo siguiente:
"Los API del sistema de archivos no son adecuados para 10s componentes de empresa de acceso a datos. Los componentes d e empresa deben utilizar un APZ gestor de recursos, como APZ JDBC, para almacenar datos."

Es cierto. Los sistemas de archivos no proporcionan apoyo para transacciones, por ejemplo. O t r o problema es que no podemos depender m6vilmente de una estructura especifica de sistema de archivos o ni siquiera de la existencia de un sistema de archivos (iYsi el contenedor EJB esti integrado en una base de datos?). Si queremos cargar un recurso, debemos utilizar el mktodo del API Java j a v a . lang. C l a s s . g e t R e s o u r c e A s S t r e a m ( ) . Si queremos cargar o almacenar datos, utihamos una base de datos o sistema equivalente.

Cargar una biblioteca nativa


S e g h la especificacion, es por razones de seguridad. Siempre que carguemos una biblioteca nativa, tenemos tambikn responsabilidades de portabilidad. iQuk sucede si necesitamos realmente codigo nativo por alguna razon? En realidad, no esti especificado en la actualidad corn0 desarrollar cualquier tipo de recurso para que acceda el EJB. Busque una soluci6n a

este problema en el API Interfaz de Conectividad de Cliente, que forma parte actualmente del Proceso de la Comunidad Java (vease http://jcp.org/).

Utilizar "this"como argument0 o valor de retorno


Esta restricci6n necesita ciertamente alguna aclaraci6n. N o podemos devolver una referencia t h i s de nuestra clase bean a1 cliente o pasarla como parimetro a una llamada de metodo a otro bean. La raz6n es que todas las interacciones con el bean deben pasar por la clase de interposicion que ya hemos analizado. Esto no significa que n o podamos pasar la referencia a la referencia de la instancia bean a una clase ayudante; podemos y probablemente lo haremos. La clase ayudante se considera parte de la clase bean y no necesita atravesar la clase de interposici6n. Ciertamente, esta es una de las dos razones por las que no deberiamos implementar la interfaz remota en nuestra clase bean. Si no implementa la interfaz, puede pasar accidentalmente como parimetro o valor de retorno para un metodo que espere esa interfaz remota. (La otra raz6n para no implementar la interfaz remota es que resulta inadecuado tener que proporcionar implementaciones in~tiles, vacias de metodos en j a v a x . e j b . EJBOb j e c t . ) Enlugar depasar la referenciathis, pase el resultado d e s e s s i o n c o n t e x t .g e t E J B O b j e c t EntityContext .getEJBObject 0.
()

Retrollamadas
N o podemos, en el caso de 10s beans de sesi6n y probablemente n o debemos, en el caso de 10s beans de entidad, utilizar retrollamadas. Las retrollamadas representan situaciones en las que EJB A llama a EJB B y EJB B llama entonces a EJB A. Las beans de sesi6n estin disefiados para que no se pueda entrar en ellos de forma reiterada. Siempre que reciben una llamada mientras procesan otra llamada, se genera una excepci6n. Si lo piensa, esta n o es una limitacibn tan importante. U n bean de sesi6n sin estado nunca intervendri en una retrollamada, porque se utilizari una nueva instancia para cada llamada de metodo. U n bean de sesion con estado no deberia ser referido por ning6n otro EJB, sino s61o por el cliente. Una llamada reentrante significa que el cliente ha llamado simultineamente desde dos hilos diferentes de la misrna transaccibn. Los beans de entidad no deberia estar diseriados para utilizar retrollamadas si es posible, porque:
0 0

El programador de bean de entidad debe disefiar el bean de entidad teniendo en cuenta esta posibilidad El contenedor no puede distinguir una retrollamada legal de una llamada concurrente ilegal en el mismo context0 de transacci6n

Probablemente podamos obtener cualquier efecto que deseemos sin recurrir a retrollamadas.

Componentes EJB en la Web


La decisi6n de utilizar tecnologia EJB en una aplicaci6n Web puede estar basada en 10s requisitos de la aplicacion para transacciones,persistencia, seguridad, reajustabilidad, etc. Sin embargo, tomar decisiones sobre tecnologia es solo el prlmer paso. iC6mo debe estructurarse una aplicaci6n Web de este tipo? Una aplicaci6n Web puede maximizar su flexibilidad y Modularidad utilizando EJB como parte de un disefio clisico de controlador de vista de modelo, model-view-controller (MVC). Este patr6n para construir interfaces de usuario se origin6 en el mundo Smalltalk y ha encontrado una aplicabilidad muy extendida en el disefio de innumerables proyectos.

Arquitectura y diseiio EIB


U n patr6n de disefio es una disposici6n de clases, de sus responsabilidades y de sus relaciones que sirve corno s o h c i 6 n reutilizable para u n problema de diseho concreto. Para rnis inforrnacih, consulte:
0

El sitio propio de J2EE de Sun en http://developer.java.sun.com/developer/technicalArticles/J2E~ patterns/Patternslntroduction. htrnl

Existen tres clases de objetos en el patron de disefio MVC:

o El modelo
El componente de datos y de lbgica de ernpresa (conocido en ocasiones corno objeto de aplicaci6n o objeto de ernpresa, dependiendo del contexto). U n modelo puede servir multiples vistas.
0

Lavista El cornponente de presentacion, tarnbikn conocido corno cornponente de interfaz de usuario. Puede haber vistas que proporcionen diferentes presentaciones de un unico rnodelo. El controlador Es el cornponente que responde a las entradas de usuario. El controlador traduce eventos de interfaz de usuario en carnbios en el modelo y despuks define el rnodo de reaccion de la interfaz de usuario ante estos eventos. El algunas versiones de MVC, la vista y el controlador se cornbinan en una unica entidad.

Estas tres clases de objetos no son componentes en el sentido en que 10s EJB son componentes: son divisiones 16gicas de funcionalidad. El objetivo de utilizar estas divisiones para disefiar una aplicacion Web es desvincular la 16gica de empresa, la 16gica de presentation y el diseiio de sitios Web. Esto tiene, corno rninirno, cuatro ventajas:
0

La aplicaci6n sera mas elistica frente al cambio. El disefio de una pigina Web puede ser alterado sin conocer la 16gica de empresa o la estructura del sitio. La 16gica de empresa o el rnodelo de datos puede ser alterado sin conocer el disefio de la pigina Web o la estructura del sitio. La estructura del sitio puede cambiar sin afectar la 16gica de ernpresa o el modelo de datos. Puede afiadirse un nuevo tip0 de interfaz, corno una aplicacion inalambrica, reemplazando simplernente la vista. Los programadores de ldgica de ernpresa, 10s disefiadores de sitios Web y 10s artistas grificos pueden trabajar de forrna independiente. U n posible punto de fa110 en una amplio proyecto de prograrnaci6n es una comunicaci6n erronea entre 10s rniernbros de un equipo. Si 10s elernentos del proyecto estin desvinculados, se precisa menos cornunicaci6n y 10s rniernbros del proyecto pueden dedicarse a su especialidad. La separaci6n entre Iogica de ernpresa, 16gica de presentacibn y disefio de sitios Web fomenta el desarrollo de especificaciones y una clara documentaci6n del c6digo. Los recursos mis caros, corno desarrolladores tkcnicos con experiencia, tienen libertad para centrarse en la parte rnis cornpleja de la aplicacion.

En esta arquitectura, el componente de modelo debe a rnenudo ser implernentado utilizando cornponentes EJB. El motivo es que 10s EJB se ejecutan en un contenedor que proporciona servicios de nivel de sistema a1 desarrollador de la aplicaci6n. Estos servicios no estin disponibles fuera del contenedor por lo que la funcionalidad del modelo (acceso a datos y 16gica de empresa) que tiene lugar en un servlet, en una pigina JSP o en un componente JavaBean no podria aprovechar estos servicios.

Capitulo 14
El componente de vista puede implementarse con piginas JSP. La tkcnica de utilizar piginas JSP para separar ldgica de empresa y de presentacidn (con JavaBeans y bibliotecas de etiquetas) ya ha sido analizada. Es una aplicacidn altamente estructurada, estas piginas JSP s61o se relacionarian con la presentacidn de datos del modelo. El componente controlador es implementado utilizando una combinacidn de un sewlet o piginas JSP, posiblemente un EJB y algunas clases de ayuda. Utilizar un controlador en un diseho de aplicacidn Web es un concept0 valioso que supera muchos de 10s problemas inherentes a1 desarrollo de aplicaciones Web. El sewlet de componente controlador o la pigina JSP recibe todas las solicitudes para URL de aplicacidn. Esta primera parte del controlador, en ocasiones denominada "componente frontal", puede garantizar que la seguridad se aplica de forma uniforme, que se inicializa el estado de aplicacidn y que no se evita el flujo de trabajo importante. Utilizar este diseho de aplicacidn significa que es ficil evitar que alguien alcance una pigina fuera de secuencia. La siguiente fase del componente controlador traduce la solicitud Web en "eventos" de aplicacidn genkricos. Esto es importante para eliminar de otros componentes de aplicacidn cualquier dependencia de 10s aspectos especificos de protocolos Web (como HTTP). Seria posible saltarse este paso per0 ello impediria que posteriores componentes fueran reutilizados en diferentes contextos.

La fase final del componente controlador es un proxy JavaBean (no un EJB), que puede reenviar 10s eventos genkricos de aplicacidn a1 controlador Enterprise JavaBean. Este controlador es responsable de cualquier actualizacidn realizada a 10s datos transaccionales de la aplicacidn, a 10s que se accede a travks de componentes EJB. Este controlador EJB devuelve una notificacidn o cualquier cambio en el modelo a1 proxy JavaBean. Este proxy puede entonces notificar las vistas JSP relevantes que el modelo ha actualizado.
Puesto que el componente de vista esti desligado de 10s componentes de modelo controlador, puede ser reemplazado por clientes diferentes. Por ejemplo, un cliente puede requerir que se le devuelva un documento HTML, mientras que otro cliente puede requerir un documento XML. Las piginas JSP que generan H T M L o XML puede ser elegidas dinimicamente en esta arquitectura. El siguiente diagrama describe una implementacidn bisica de una implementacidn de un controlador MVC para un sitio Web:

Controlador

Cl~ente navegador

Arquitectura y disefio JB
El cliente navegador realiza una solicitud H T T P (GET o POST) [I]. Todas estas solicitudes se dirigen a1 "componente frontal", que en este caso es una pagina JSP llamada main. La implementaci6n del controlador (que puede ser un JavaBean, un EJB o una combinaci6n de ambos) actualiza el modelo si es necesario reenviando el evento de interfaz de usuario, posiblemente en forma transformada o normalizada [2]. El controlador selecciona una vista para su presentaci6n [3], que se actualiza entonces a si misma frente a1 modelo [4]. La salida de la vista es devuelta a1 cliente [5].

Sun tambie'n proporciona un ejemplo de esta arquitectura en su documento J2EE Blueprints, en forma de un sitio de comercio electrdnico que vende mascotas en la Web. La versidn de Sun aiiade dos niveles adicionales de abstraccidn, introduciendo un nivel que traduce eventos Web en eventos de aplicacidn y proporcionando arquitectura de notif;:cacidn de eventos entre el modelo y las vistas (que almacenan en la cache' algunos datos del modelo). Si estci interesado en explorar este tema ma's alla' de lo que presentamos en este libro, puede descargar el documento Blueprints desde el sitio Web de Sun en http:lfiava.sun.comfi2eelb/ueprints.

Acceso de nivel cliente a EJB


En ocasiones, la 16gica de presentaci6n y el flujo de trabajo se manejan en el nivel cliente, como es el caso de una aplicaci6n Visual BASIC. Una aplicacion de este tip0 puede todavia implementar el patr6n de controlador de vista de modelo (MVC) en el lado cliente, pero no existiria necesariamente la necesidad de proporcionar este nivel de estructura en el servidor. Puede que todavia existiera la necesidad de aprovechar 10s servicios que puede proporcionar un contenedor EJB. En 10s casos en 10s que 10s servicios Web no son necesarios, una aplicaci6n cliente probablemente accederia directamente a EJB. mas sencillo, un cliente puede acceder a un Enterprise JavaBean de forma remota utilizando En el RMI. Este es el caso del cliente G U I Java. U n cliente escrito en un lenguaje distinto a Java puede acceder tambien a un EJB directamente utilizando I I O P ( o el Internet Inter-ORB Protocol, un protocolo estandar que permite a CORBA Object Request Broker (ORB) interoperar).

case

Para que esto suceda, el servidor de aplicacidn tambit% debe funcionar como un C O R B A O R B . El transporte de comunicacidn I I O P se convierte en obligatorio en la especif;:cacidnborrador EJB 2.0 y todos 10s servidores de aplicacidn ad~ptadostendra'n funcionalidad O R B .
Otra posibilidad que ofrece maxima flexibilidad en tkrrninos de acceso de cliente es un modelo EJB cuyos datos son transformados por un servlet "vista". El API Servlet provee servlets que son capaces de enviar y recibir datos arbitrarios en un formato "solicitudlrespuesta". U n cliente que requiere que se utilice un formato concreto para comunicar con el servidor, puede utilizar un servlet para mediar las comunicaciones con 10s EJB que necesita:

Apl~cac~bn PowerBu~lder

-h

Servlet

I, r
I

Enterpr~se JavaBeans

Entonces, +indo seri apropiada esta arquitectura de acceso directo (con o sin un objeto "vista" mediador)? Este es el disefio que se utilizaria para implementar una aplicacidn de servidor cliente. Elegir entre acceso directo a EJB y acceso Web a EJB es con frecuencia lo mismo que elegir entre una aplicaci6n Web de "cliente infradotado" y una aplicaci6n de servidor cliente de "cliente robusto" (pero de tercer nivel).

Capitulo

1 4

Muchos factores pueden influir e n esta d e c i s i h , como requisitos de interfaz de cliente y temas de distribuci6n deaplicaci6n. Una regla bisica es que el acceso a Internet (o cualquier acceso distribuido) por parte de un amplio grupo de usuarios indicari habitualmente que se requiere una aplicaci6n Web y el acceso a datos de empresa debe ser mediado por un componente vista y un componente controlador en el nivel Web. O t r a regla bisica es que 10s usuarios de una red local esperarin con frecuencia un nivel de servicios de cliente que pueden requerir un cliente G U I independiente, en lugar de un navegador Web; este G U I independiente p e d c acceder directamente a1 nivel Enterprise JavaBeans. Los applets Java son el comodin, combinando las ventajas de distribucion de una aplicaci6n Web con las capacidades de presentacidn de un G U I independiente. En lugar de invocar un metodo en un EJB directamente utilizando RMI, accederin en ocasiones a EJB a travCs de un senlet, utilizando H T T P para superar cortafuegos colectivos. Por supuesto, no hay nada que nos impida acceder directamente a un EJB desde un servlet para proporcionar una sencilla pigina Web, en lugar de utilizar la arquitectura MVC. Si tenemos una aplicaci6n Web de alcance limitado y un EJB existente que queremos reutilizar, este enfoquepuede resultar apropiado. Ademis, si tenemos una aplicacion Web con necesidades limitadas de presentacidn y navegacibn, per0 con importantes requisitos de 16gica de empresa y acceso de datos, puede que nos encontremos accediendo directamente a un EJB desde un s e n l e t o desde una clase ayudante de la pagina JSP. Antes de aplicar este enfoque a una aplicacion Web, debemos considerar detenidamente si hay alguna posibilidad de ampliar el alcance del proyecto, ahora o en el futuro.

Diseno del nivel EJB


Hasta este punto, el andisis sobre disefio de aplicaciones que utilicen Enterprise JavaBeans ha ignorado esencialmente el disefio del nivel EJB. En el desarrollo de 10s componentes EJB para una aplicacion, irnplementamos fundarnentalrnente un modelo de nuestra empresa. El diseno de este nivel debe ser ampliamente independiente del disefio del nivel Web o del nivel cliente. Esta independencia fomenta la reutilizaci6n de la 16gica de empresa y 10s componentes de acceso a datos, que en muchos sistemas son la parte mas dificil y cara de desarrollar. Tamhien permite el cambio de la logica de presentaci6n con independencia de la ldgica de empresa. Este es un objetivo de disefio importante para muchos sistemas, ya que la 16gica de presentacidn tiende a ser mas volitil que la ldgica de empresa.
p p p p p p p p p p p p p p -

Ejemplos de uso de UML


Unified Modelling Language (ULM) es el lenguaje estindar para expresar el modelo de sistemas de software. Los ejemplos de uso son un subgrupo de ULM que expresa la funcionalidad que deheria proveer el software, percibida por actores externos (alg6n elemento exterior a1 software, como una persona u otro sistema de software). U n dnico ejemplo de uso especifica una funci6n complera, como "realizar un pedido" o "presentar la evaluacidn de un empleado". Los ejemplos de uso describen q u i hacer per0 no cbmo hacerlo. C o m o son realmente implementados por el software resulta irrelevante en esta etapa del proceso de disefio.
En la actualidad, n o existe apoyo directo para 10s componentes Enterprise JavaBeans en el U L M . Sin embargo, se estd desarrollando u n 'perfiil" U L M p a r a Enterprise JavaBeans en el Proceso de la Comunidad Java (JCP). Este perfil es u n conjunto de extensiones que permitirian a U M L expresar directamente (de forma estkndar) la estructura y sema'ntica especi$ca d e 10s EJB. Esto garantizaria que 10s modelos fueran mo'viles en herramientas d e dqerentes vendedores. Para mds detalles, 10s lectores pueden remitirse a1 documento de solicitud d e especificacio'n en http:llwww.jcp.orgl aboutlavalcommunityprocess/review/jsrO26/. (Es converiierite destacar que las herramientas U L M

Arquitectura y diseio U B
como "Rational Rose" y "Together j" ban proporcionado recientemente funciones que incluyen el modelado de un EJB.)
U n desarrollador EJB debe ser capaz de traducir un ejemplo de uso e n una implementacidn funcional. La funcionalidad de un ejemplo de uso c o n ~ i e n z a cuando u n actor realiza una solicitud a1 sistema. N o finaliza hasta que el software ha cumplido el objetivo representado p o r la solicitud. C o m o quizis se necesite gran cantidad de cddigo para implementar cada ejemplo de uso, la correspondencia entre ejemplos de uso y EJB n o es exacta. D e hecho, se utilizardn m~iltiples EJB para implementar la mayoria de 10s ejemplos de uso y tanto 10s beans de sesi6n c o m o 10s beans de entidad se utilizan en ambas situaciones.

Objetos de analisis
E n U L M , un modelo de ejemplo de uso se realiza modelando clases que implementen ese ejemplo, junto con sus relaciones e interacciones. El procedimiento exacto para modelar un ejemplo d e uso (el proceso, 10s diagramas) es irrelevante para comprender c 6 m o representar un ejemplo de uso por EJB. Resulta Gtil considerar tres tipos de objetos d e analisis que el inventor de 10s ejemplos de uso, Ivan Jacobson, describi6 a partir de su experiencia en la construccion de grandes sistemas mantenibles de software y considerar c o m o pueden expresarse estos tipos de objetos utilizando EJB.

Objetos interfaz
El objeto interfaz (tambikn conocido c o m o objeto frontera) es responsable del control de acceso a1 nivel EJB desde cualquier cliente. Esto incluye otros componentes de lado servidor, c o m o servlets y pdginas JSP. U n escelente ejemplo de u n objeto interfaz es el servlet controlador para la arquitectura de controlador de vista de modelo de la aplicaci6n Web. (Observe que estamos utilizando la palabra "interfaz" genkricamente y n o en el sentido de la palabra clave interfaz del lenguaje Java.) U n objeto interfaz s i e m p r e debe ser representado p o r u n bean d e sesi6n e n la implementaci6n. Las capacidades del cliente y 10s requisitos de la aplicaci6n especifica determinarin si el bean de sesion deben tener o n o estado.

Objetos control
Los objetos control proporcionan servicios a la aplicacion. Modelan la funcionalidad que n o estd naturalmente asociada c o n una determinada entidad o interfaz. C o n frecuencia, esto se debe a es necesario procesar mds de una entidad; un ejemplo podria consistir en determinar si hay suficiente inventario para manufacturar un producto. E n otras ocasiones, puede deberse a que una entidad relevante n o ha sido identificada en el modelo; un ejemplo podria ser cargar un gasto a una tarjeta de crkdito. Los objetos c o n t r o l d e b e n ser representados p o r beans d e sesi6n e n la i m p l e m e n t a c i 6 n ( t a m b i i n puede utilizarse m i t o d o s d e empresa d e interfaz bisica para i m p l e m e n t a r objetos control). Debido a que pueden ser invocados desde otros EJB, 10s objetos control siempre deben ser sin estado. El estado conversacional del nivel EJB, si existe, siempre debe mantenerse e n un objeto interfaz, para evitar complejidad y mejorar la reajustabilidad.

Objetos entidad
Los objetos entidad modelan aquellos objetos de empresa que deben mantener su estado despuks de concluir el caso de uso. Habitualmente, esto significa que representan datos desde la base de datos.

Capitulo 14
Algunos ejemplos son un comprador, un producto, un pedido, una evaluaci6n de personal, un evento de red o un plazo miximo para un proyecto.

Los objetos entidad son a menudo, per0 no siempre, representados por beans de entidad en el modelo de implementaci6n. En ocasiones, estPn representados por objetos dependientes dentro de un bean de entidad y a veces son implementados sin ninguna representaci6n de objeto (por ejemplo, por c6digo JDBC en un bean de sesi6n).
Por supuesto, existen infinitos esquemas de clasificaci6n por lo que puede organizar su modelo de objeto. Jacobson eligi6 tres clasificaciones porque creia que 10s sistemas mis estables estaban disefiados de forma que 10s cambios realizados a1 sistema pudieran mantenerse tan aislados como fuera posible. Observe que esto es tambikn una motivaci6n para el principio mas general de separar bgica de disefio de logica de empresa. i C 6 m o ayudan estos tres tipos de objetos a garantizar que 10s cambios efectuados en el sistema se mantienen localizados en una pequefia parcela de la implementaci6n? Hay dos diferencias primarias entre esto y un simple modelo de objeto que s610 representa entidades como productos, compradores, empleados o contratos: Los objetos interfaz protegen a 10s otros tipos de objetos de la volatilidad de otros niveles de la arquitectura. Como regla general, cuinto mayor sea el recorrido desde el modelo de datos hasta el cliente, mis probable seri que la implementaci6n necesite un cambio. La lbgica de empresa en el nivel EJB cambiari gradualmente a medida que vayan cambiando las politicas que representa. El disefio de una aplicacion Web puede sufrir una revision continua a medida que 10s usuarios descubran nuevas oportunidades de mejorar la productividad y la conveniencia. Los cambios de la interfaz s61o deben afectar a1 objeto interfaz.

o Los objetos control preservan la localization de funciones que atraviesan mcltiples entidades
reales. Por supuesto, es posible romper esta funcionalidad y asignarla a las entidades afectadas, puesto que las entidades modelan comportamiento y datos de representaci6n. Sin embargo, cuando llega el momento en que esta funcionalidad necesita ser modificada, es mis ficil si puede ser cambiada en un lugar. Los modelos de anilisis de ejemplos de uso no son desarrollados de forma aislada. Los objetos adecuados de anilisis son con frecuencia determinados en un proceso iterativo que conlleva la consideraci6n de m61tiples ejemplos de uso. Como regla bisica, un objeto interfaz representari acceso a un grupo de ejemplos de uso relacionados para una determinada clase de usuarios a travis de un metodo particular (que puede ser a travks de una aplicacion Web, un cliente GUI, un protocolo XML de cliente a cliente como SOAP o XML-RPC, un sistema ERP o casi cualquier otra cosa). U n objeto control representari a menudo las actividades asociadas a un unico ejemplo de uso.

Analisis versusimplementacion
Del mismo modo que no existe una correspondencia exacta entre ejemplos de uso y EJB, tampoco existe correspondencia exacta entre objetos de anilisis (interfaz, control y entidad) y componentes EJB. Los objetos de anilisis son creaciones logicas que deben ser asociadas a clases de implernentacion reales. Ya hemos visto un ejemplo de esta falta de correspondencia exacta en el disefio de aplicaciones Web MVC, donde el objeto interfaz produce dos niveles: el bean de sesi6n controlador (nivel EJB) y el JavaBean de proxy (nivel Web). iPor quk debemos realizar un anilisis que no tiene como resultado un modelo de objeto que podemos implementar directamente utilizando Enterprise JavaBeans? Los objetivos de la fase de anilisis son

Arquitectura y diseho EJB


proporcionar una estructura flexible para nuestra aplicaci6n y comprender como debe dividirse la funcionalidad entre roles de cornponentes (interfaz, entidad o control). Una vez establecida esta estructura, podemos entonces considerar 10s efectos de las herramientas de implementaci6n y de la arquitectura de componentes en nuestro disefio. En este caso concreto, obviamente, debernos considerar las capacidades y limitaciones del entorno de implementaci6n EJB.

En ocasiones, un modelo de dise6i0, cuyo propdsito es refinar y formalizar el modelo de ana'lisis, entrara' en juego antes de que se tenga en cuenta el entorno de imp/ementacidn. El proceso exacto es irrelevante para comprender 10s efectos del uso de la tecnologia EJB en el disefio de la ap/icacidn.
La limitaci6n mis importante y la que dirige un modelo de implementaci6n desde un punto de vista arquitect6nic0, es que 10s EJB son componentes pesados. Esto significa que hay coste en la implementaci6n de un objeto como un EJB, que debe ser tenido en cuenta. El coste existe por dos razones: 0 Los EJB pretenden ser accesibles para clientes remotos. Cualquier comunicaci6n en la red tiene costes asociados.
0

Los servicios proporcionados por el contenedor EJB tienen costes de configuraci6n. El contenedor debe emprender acciones para proporcionar cada acceso de 16gica de empresa de un componente que protecci6n de accesos no autorizados, apoyo para usos transaccionales y transferencia controlada de datos de empresa, de mod0 que el acceso a un componente EJB pueda considerarse relativamente caro.

C o m o consecuencia de ser componentes pesados, 10s EJB se utilizan a menudo para representar una agregaci6n de objetos que existen en el modelo de anilisis. Estos otros objetos quizis tengan una correspondencia en la implernentaci6n pero quizis sean objetos Java ligeros (como componentes JavaBeans), en lugar de EJB. Ademis, la funcionalidad que podria ser representada por operaciones multiples sobre objetos de anilisis debe transformarse en una unica operacion sobre un objeto de la implementaci6n. Consideremos c6mo se aplicaria esta agregaci6n de objetos o funcionalidad a 10s tres tipos de objetos del modelo de anilisis:

o Los objetos interfaz serin representados normalmente por un unico objeto para cada usuario
externo en el modelo de anilisis y un dnico bean de sesi6n en el disefio. Sin embargo, las operaciones disponibles para la interfaz de usuario probablemente necesitaran ser agegadas a la implementaci6n. U n buen ejemplo es el acceso a atributos de modelo. Los mktodos de o b t e n c i h o configuraci6n normalmente n o son apropiados para objetos remotos porque cada llamada para obtener o configurar datos significa otro recorrido por la red. Por lo tanto, el objeto interfaz necesitari aceptar y devolver algun tip0 de colecci6n en respuesta a actualizaciones y recuperaciones de datos. Dependiendo de la situaci6n y de las capacidades del cliente, puede que sea posible referenciar directamente un objeto control. Si n o se requiere ninguna funcionalidad especifica, n o debe desarrollarse ninguna sesi6n de interfaz.
0

Los objetos control con frecuencia corresponden a un unico caso de uso en el modelo de anilisis. Este objeto de modelo de anilisis contiene la logica de empresa necesaria para ejecutar una secuencia de operaciones, modificar y recuperar datos desde objetos entidad relevantes, y validar 10s resultados. En la implementaci6n, un caso de uso tendri normalmente una representaci6n en un unico metodo del EJB de sesi6n de interfaz. Por ejemplo, el caso de uso "realizar un pedido" podria tener un rnetodo correspondiente en el EJB de sesion de interfaz placeorder (CustomerInfo, Shoppingcart).Lafuncionalidadde control especificadel tip0 de usuario seri implementada probablemente justo en ese objeto interfaz, directamente o como objeto ayudante, dependiendo de su complejidad. Sin embargo, en muchos casos, la

funcionalidad de objeto control seri comun a multiples casos de uso. Por ejemplo, multiples casos de uso quizis requieran funcionalidad de realizaci6n de pedido. La funcionalidad de control cornfin a multiples casos de uso debe ser trasladada a un bean de sesi6n o a multiples beans de sesi6n que proporcionen servicios reutilizables. En este caso comun, la funci6n del bean de sesi6n de interfaz de la implementaci6n seri traducir la solicitud a una forma genkrica, para garantizar que las reglas de flujo de trabajo no son violadas y para invocar 10s beans de nivel de servicio adecuados. Los beans de capa de semicio serin implementados como beans de sesi6n sin estado. La combination de beans de sesi6n de interfaz mis beans de sesi6n de capa de semicio compondri el objeto control.
O Los objetos entidad cuentan con la mayor variacidn en su desviacidn del modelo de anilisis.

Incluso durante el anilisis, a veces resulta dificil identificar quk debe ser modelado como atributo (es decir, "variable de miembro") y que debe ser un objeto de dominio (es decir, una "clase"). Esto resulta incluso mas dificil en la implementaci6n, porque 10s objetos entidad son con frecuencia 10s tipos rnis pesados de todos 10s Enterprise JavaBeans. Esto se debe a que se accede a ellos en grandes cantidades. En un caso de uso concreto, puede haber un bean de sesidn de interfaz, tres o cuatro beans de sesi6n que proporcionan funcionalidad de control y potencialmente cientos ( o incluso miles) de beans de entidad participantes. Asimismo, 10s beans de entidad necesitan cargar su estado desde la base de datos, una operacidn relativamente cara en muchos entornos. N o es usual que entidades de primera clase en el modelo de anilisis Sean representadas por atributos en la implementacion o modelados como JavaBeans. Incluso es posible implementar objetos entidad como clases de acceso a datos utilizados por beans de sesidn y excluir por completo beans de entidad de su implementaci6n. (Puesto que 10s beans de entidad proporcionan importantes servicios persistentes, esto no se recomienda habitualmente.) Nuestra eleccion de tecnologia tiene un efecto sobre el disefio final. U n o de 10s factores mas importantes seri las capacidades de asociaci6n de objeto/relacionales de 10s productos que elijamos. Algunos servidores de aplicaci6n compatibles con EJB, incluso algunos de 10s mis conocidos, s610 tienen apoyo limitado para mantener automiticamente objetos entidad complejos para tablas relacionales subyacentes. Si este es el caso de su servidor de aplicacidn, tiene varias opciones. En ocasiones, podemos adquirir productos de ampliacion que proporcionarin persistencia gestionada por contenedor en cooperaci6n con el semidor de aplicaci6n. Podemos elegir una herramienta de asociacion de objeto/relacional que no este directamente apoyada por nuestro contenedor. En este caso, tenemos la opcion de utilizar objetos entidad con persistencia gestionada por bean o beans de sesidn que actualizan la base de datos directamente. Una regla importante que debemos recordar es que 10s beans de sesibn no estin diseiiados para representar datos transaccionales. U n bean de sesi6n puede actualizar la base de datos, per0 n o debe modelar 10s datos directamente. Esto se debe a que no cuenta con las retrollamadas del contenedor y la gesti6n de 10s beans de entidad para permitirles participar de forma inteligente en transacciones, accesos concurrentes sincronizados, repuestas a errores, etc. finalmente, podriamos elegir modelar objetos dependientes como beans de entidad. h a no es una situation ideal pero, con este enfoque, el apoyo para correctas asociaciones de base de datos esti pricticamente garantizado con un contenedor EJB. Los requisitos de reajustabilidad quizis afecten a nuestra eleccion de tip0 de componente a1 implementar un objeto interfaz. Resulta mis car0 mantener el estado conversational en el servidor que en el cliente. La elecci6n de bean con sesi6n o sin sesiSn para 10s componentes de interfaz se basari a menudo en el volumen de uso planificado para la aplicaci6n. Obviamente, almacenar estado en diferentes niveles puede tener como resultado implementaciones notablemente diferentes.

La funcion de estado en el objeto interfaz


La especificacion EJB proporciona dos tipos de beans de sesi6n: con estado y sin estado. Los beans de sesidn sin estado siempre se utilizan en el nivel de seyicios. Elegir un tip0 de sesion para el objeto

Arquitectura y diseiio U B
interfaz es mis dificil. Permitir que la interfaz tenga estado quizis simplifique el disefio de la aplicaci6n. Por ejemplo, un cliente tip0 navegador Web quizis no puede gestionar el estado de forma tan efectiva. Sin embargo, casi siempre es posible mantener el estado en un nivel mis cercano al cliente. Una de las principales ventajas de mantener estado conversacional en un bean de sesi6n de objeto interfaz es aplicar el flujo de trabajo de un caso de uso o grupo de casos. Considere una situaci6n en la que, antes de realizar una adquisici6n, un visitante de la Web debe registrarse y permitir a la aplicacidn que recupere la informacidn relevante del comprador o crear un registro de comprador con informaci6n de pedido, informaci6n de contacto, e-mail opcional y preferencias de sitio. Un objeto interfaz de bean de sesi6n con estado podria aplicar este requisito. U n bean de sesidn sin estado necesitaria depender de la interfaz de usuario para ello porque no podria recordar las acciones del comprador entre las llamadas de metodo.

Un ejemplo de diseno EJB


En 10s siguientes capitulos, construiremos una pequeiia aplicaci6n de muestra. Por el momento, la mayoria de programadores saben que se puede construir una aplicaci6n de comercio electr6nico con tecnologia EJB. Es comprensible que este espacio de aplicaci6n se tom4 como referencia con tanta frecuencia; muchos de 10s interesados en programaci6n Java de lado servidor quieren escribir aplicaciones compatibles con operaciones comerciales en la Web. Sin embargo, las tecnicas bisicas son aplicables a casi cualquier sohci6n Java de lado servidor, asi que, para variar, utilizaremos un ejemplo mis elaborado. En este capitulo, consideraremos su disefio. Considere el caso de una compaiiia que desarrolla productos, admite pedidos y despues 10s manufactura y envia. Algunos requisitos iniciales sencillos podrian ser 10s siguientes:

O El departamento de ingenieria necesita poder definir un producto como una serie de pasos que seguiri la instalaci6n de fabricaci6n para elaborarlo. O Necesitamos poder admitir pedidos en la Web y por telefono utilizando operadores que registren 10s pedidos de nuestros agentes de ventas. Necesitamos poder notificar a1 departamento de manufacturas que se ha realizado un pedido de un determinado producto, que debe ser entregado en una fecha concreta. El identificador para este pedido es exclusive en una divisi6n concreta de ventas per0 cada divisidn de ventas tiene su propio esquema de numeracidn y pueden existir numeros de pedido duplicados entre divisiones.
0 Necesitamos poder cancelar un pedido cuya manufactura todavia no ha comenzado. Necesitamos

poder evitar la cancelacion de un pedido cuya elaboracidn ya ha comenzado.

O El departamento de manufacturas necesita seleccionar un pedido apropiado de manufactura, basado en el tiempo requerido para elaborar un producto y el plazo miximo que la compafiia lo retendri en inventario.
0 El departamento de gesti6n debe poder recuperar una lista de pedidos atrasados.
0

El departamento de manufacturas debe poder notificar a1 departamento de envios que un producto esti listo para envio. Debe indicar la empresa de transportes apropiada a1 tamafio y peso del producto elaborado y el almacen de carga al que ha sido enviado. Debe poder identificarse, en caso de que haya un problema de calidad con el producto y registrar la fecha completa, para responder a consultas de clientes.

Para esta hipotetica compafiia, podemos identificar seis actores:

O U n ingeniero

U n cliente Web

Capitulo 14
o U n operador de telkfono que registra pedidos de un catilogo
O

U n gestor de planta que gestiona el proceso de manufactura

o U n miembro de plantilla que elabora realmente el producto solicitado o U n gestor que hace un seguimiento de 10s pedidos atrasados
TambiCn habri siete casos de uso:

o Crear un producto o Realizar un pedido o Cancelar un pedido


O Seleccionar un pedido para su manufactura
O O

Elaborar un producto Enviar un pedido

O Registrar pedidos atrasados


~ s t es e un diagrama de casos de uso que podria resultar de nuestro anilisis:

Crear un Producto

Comprador We

Telefon~co
r a w Manufactura

estor de Planta

Elaborar un Producto M~embro de Plantllla Env~arun Pedido Departamento de Gest~on Reg~strar Ped~dos Atrasados

Arquitectura y diseiio EJB


Consideraremos 10s detalles sobre las tareas que realizaremos para conseguir cada caso de uso. Los pasos de cada caso de uso que implementaremos en realidad en nuestro ejemplo estin destacados en negrita.

Crear un producto
Seleccionar una etiqueta de identificacidn de producto y u n nombre descriptivo de producto
O O
O

Afiadir 10s pasos de direccionamiento que seguiremos durante la fabricacidn del producto Crear 10s registros de inventario necesarios que gestionan el proceso de fabricaci6n de este producto Establecer el precio

Realizar un pedido
o Calcular el precio total del pedido o Validar el metodo de pago
O O

Registrar el pedido Devolver information de registro de pedido a1 comprador

O E-mail de confirmaci6n del pedido

Cancelar un pedido
O

Asegurar que el pedido n o esti siendo fabricado ya

o Cambiar el estado del pedido a cancelado


O O

Abonar la cantidad a la cuenta o tarjeta de crkdito del comprador E-mail de confirmaci6n de la cancelaci6n

Seleccionar un pedido para su manufactura


o Enumerar 10s pedidos elegibles, definidos como aquellos en 10s que el estado esti abierto, y la
fecha de hoy es mayor que la fecha de vencimiento del pedido menos el tiempo de elaboracih, menos el tiempo que pendbamos tenerlo en el inventario
0 Elegir u n o de ellos para elaborar el producto correspondiente

O O
O

Asegurar que existe suficiente inventario Degradar el inventario Comprobar 10s niveles minimos de inventario; contactar con 10s proveedores si es necesario

Elaborar un producto
o Iterar 10s pasos de redireccionamiento definidos para el producto, siguiendo las instrucciones

Enviar un pedido
Indicar el medio de transporte elegido y el almackn de carga a1 que sera trasladado el producto elaborado

Capitulo 1 4

Registrar pedidos atrasados


0

Registrar 10s pedidos atrasados, definidos como aquellos e n 10s que el estado e s t i abierto y la fecha de hoy m i s el tiempo requerido para la fabricaci6n es superior a la fecha de vencimiento o aquellos donde el estado es "en proceso", y la fecha de hoy es superior a la fecha de vencimiento

Implementaremos dos grupos de interfaces a esta aplicaci6n: un grupo de clientes Java independientes y una aplicaci6n Web. C o n objetivo del anilisis, utilicemos nuestra imaginacion y concibamos que existen otros clientes: un G U I Swing que utiliza el operador de telkfono; una aplicaci6n Visual BASIC que utiliza el personal de ingenieria; y una interfaz Palm Pilot que utiliza la plantilla de fabricacion (el resto de clientes utilizara interfaces Web). Para cada aplicacion cliente, existe un objeto interfaz en nuestro modelo de anilisis. ULM tiene un mktodo de extension, llamado estereotipo, que "especializa" un elemento definido en el lenguaje de modelado. U n estereotipo puede ser representado por texto entre parkntesis (<<interfaz>>) o rodeado de un icono. Los objetos inrerfaz, 10s objetos control y 10s objetos entidad tienen estereotipos estindar, con represenraciones de iconos. El icono de estereotipo para un objeto inrerfaz en ULM tiene este aspecto:

Inspeccionando 10s casos de uso, podemos identificar 10s siguientes objetos entidad en el modelo de anilisis (10s que realmente utilizamos en nuestra implementaci6n simplificada estin en negrita):

o Producto
0 Pedido

o Paso de redireccionamiento
O
0

Envio Cuenta

O Proveedor O

Empresa de envios

o Comprador
El estereotipo para un objeto entidad en ULM tiene este aspecto:

Arquitectura y disefio EJB

Habitualmente, existe una correspondencia exacta entre casos de uso y objetos control. Los objetos control aqui serian:

u
u

Crear un producto Realizar un pedido Cancelar un pedido Seleccionar un pedido para su manufactura Elaborar un product0 Enviar un pedido Registrar pedido atrasados

u u u u u

El estereotipo para un control objeto en ULM tiene este aspecto:

Examinemos tres vistas diferentes de un posible modelo de anilisis. La primera vista muestra 10s actores de caso de uso y sus respectivos objetos interfaz:

Capitulo 14

Cornprador Web

Operador de Telefono

Gestor de Planta

'

fipl~cac~bn Palm P~lot

Departarnento de Gest~bn

La segunda vista muestra 10s objetos interfaz y 10s objetos control con 10s que interacthn:

Arquitectura y disefio EJB

Crear Producto

Web

Ped~do

Cancelar Ped~do
-

I
I

Manufactura
-

- - -

. .

Elaborar Producto

Finalmente, la tercera vista muestra c6mo 10s objetos control interactca con objetos entidad. Observe c6mo el modelo objeto, incluso para aquello que parece un problema insignificante, es suficientemente complicado y probablemente es mejor verlo en segmentos con una herramienta de modelado que dibujarlo todo de una vez:

Capitulo 14

Crear Producto

7 Producto

Cancelar Pedldo

Reg~strar Atrasos
--

Cornprador

Afortunadamente, esta complejidad permanece oculta para cualquier interfaz de usuario por 10s objetos interfaz. Fijese tambiin en que una funcionalidad corno "realizar un pedido" podria haber estado localizada en 10s objetos pedido, producto, cuenta y comprador. Sin embargo, esto hubiera aumentado el irea de superficie de nuestro disefio. El rnodelo de anilisis necesita ahora ser traducido en una implementacidn apropiada para nuestro entorno. C o m o hemos destacado anteriormente, esto no s e d una sencilla traduccion de correspondencia exacta desde objeto de anilisis a cornponente EJB. Cornencemos considerando 10s objetos interfaz: Actor Tipo de interfaz de usuario Visual Basic Aplicacion Web / piginas JSP G U I Swing Aplicacidn Web / piginas JSP Palm Pilot XHTML Aplicacion Web I piginas JSP Implementaci6n de objeto interfaz Bean de sesi6n (RMI-IIOP) Proxy JavaBean/ Bean de sesi6n Bean de sesidn JavaBean proxy / Session Bean Proxy JavaBeanl Bean de sesidn Proxy JavaBean / Bean de sesi6n

I Operador Telf. I Gestor de plants I Miembro de plantilla


I
Dept. Gesti6n

Ingeniero Comprador Web

Arquitectura y diseho EIB


Observe que, en cuatro de 10s seis casos, el objeto interfaz del modelo de anklisis podria traducirse en .mriltiples componentes sobre mriltiples capas.
U n detalle que no resulta evidente en esta tabla es que no hay necesariamente seis beans de sesi6n diferentes. El operador de telkfono, el comprador Web y el comprador empresa-a-empresa pueden compartir una unica interfaz de bean de sesi6n. Quizis recuerde el anilisis anterior sobre la arquitectura de controlador de vista de modelo (MVC). Habia una clase en el componente controlador responsable de traducir solicitudes Web en eventos de aplicaci6n genkricos. Esta traducci6n posibilita la consideraci6n de reutilizar el bean de sesi6n para mis de una interfaz. Por supuesto, tambikn puede ser que 10s requisitos de las diferentes aplicaciones necesiten la provisi6n de funcionalidad personalizada. En este caso, se utilizarian 10s diferentes objetos interfaz. Por ejemplo, en el mundo real, 10s compradores Web y 10s compradores de nuestros agentes de ventas quizis obtengan precios diferentes, diferentes proceso de aprobaci6n de crkdito, diferentes limites en 10s pedidos, pedidos de remesas directas en lugar de entregas de inventario, etc., dependiendo del perfil del comprador. Consideremos a continuaci6n 10s objetos entidad. Asumamos que tenemos un semidor de aplicaci6n con capacidades adecuadas de asociaci6n objeto-relational. Ademis, asumamos que vamos a utilizar beans de propiedad alli donde sea necesario, de mod0 que podamos aprovechar 10s semicios de persistencia de nuestro contenedor. Son a1 menos dos 10s cambios que vamos a realizar desde el modelo de anilisis a la implementaci6n. Primero, vamos a degradar 10s pasos de redireccionamiento desde un objeto de empresa de primera clase (es decir, un componente) a un atributo del producto (es decir, una variable de miembro). Esto se realiza reconociendo el hecho de que 10s beans de entidad son objetos pesados y no queremos que cada uso de un articulo de linea haya pasado por la capa de semicios del contenedor. Una regla bisica comun es que 10s objetos cuyo ciclo de vida (creaci6n y destrucci61-1) esti completamente controlado por otro objeto deben ser atributos de dicha entidad EJB, incluso si hubiera objetos de primera clase en el anilisis.

U n contenedor EJB tiene muchas oportunidades de optimizar llamadas ')esadas" entre componentes que se esta'n ejecutando en el misma Equipo Virtual Java. El alcance del contenedor en este aspect0 varia ampliamente entre vendedores.
En segundo lugar, modelaremos 10s envios como un semicio de bean de sesi61-1,en lugar de c6mo una entidad. La intenci6n es simplificar el desarrollo. La aplicaci6n de elaboraci6n no necesita acceder a informaci6n de envio una vez en la base de datos. Tener un unico mktodo de empresa que utiliza SQL seria mejor que escribir un bean de entidad cuyo unico prop6sito eraser creado, en tkrminos de coste de desarrollo. Finalmente, consideremos 10s objetos control. En el modelo de anilisis habia siete: Crear un producto, Realizar un pedido, Cancelar un pedido, Seleccionar un pedido para su manufactura, Elaborar un producto, Enviar un pedido y Registrar pedidos atrasados. Podriamos conseguir que siete beans de sesi6n representaran estos objetos control. Pero, ademis de tener objetos pesados en el period0 de ejecuci61-1,10s EJB tambikn tienen cierta cantidad de peso en el proceso de desarrollo. Cada EJB debe tener como minimo tres archivos Java e informaci6n de configuraci6n. Consemando el resto de elementos, un EJB es mejor que tres. Realizar, cancelar y registrar pedidos parecen lo suficientemente coherentes para . aiiadirlos a un unico bean de semicio ("Gestionar pedidos"). Del mismo modo, seleccionar un pedido para su manufactura, elaborar el producto y enviar el pedido, tienen lugar en la planta de fabricaci6n ("Manufactura"). El objeto control "Crear un producto" contari con un bean de sesi6n propio. Tendremos que considerar si podemos combinar cualquier objeto control y objeto interfaz en un unico bean de sesi6n. La respuesta dependeri de la complejidad de nuestro sistema y de 10s requisitos para la reutilizaci6n de componentes. Podemos reutilizar una implementaci6n de bean de sesi6n de un objeto control mis ficilmente que un bean de sesi6n que implemente tanto la interfaz como la 16gica de control. Son las mismas razones que presentamos anteriormente para diferenciar entre interfaz y 16gica de control

Capitulo 14
en el modelo de anilisis (localizaci6n de cambios). Adicionalmente, si su objeto interfaz tiene estado, no puede ser reutilizado en por otros componentes EJB, ya que su estado debe pertenecer a un inico cliente. Tenemos que considerar un hltimo punto: 2hasta qu6 punto debemos factorizar funcionalidad adicional a sus propios EJB de sewicio de sesi6n sin estado? Si existiera una descripci6n de la implementacidn de software completa de nuestra empresa, podriamos detenernos en este punto. Ciertos aspectos de la funcionalidad de 10s objetos de control serian probablemente implementados como clases de ayuda JavaBean, pero seria un detalle de implementaci6n irrelevante para el sistema EJB. Sin embargo, es mis probable que necesitiramos considerar qu6 sewicios podrian ser utilizados por otros objetos,control en partes del software que no han sido descritas. Por ejemplo, es probable que la comprobaci6n de 10s niveles de inventario se realizara por el software de contabilidad o de gesti6n. Por ello, la funcionalidad para comprobar 10s niveles de inventario se convierte en bean de sesi6n sin estado que proporciona mktodos relacionados con el inventario. Tenemos otro ejemplo en el e-mail que enviamos 10s casos de uso. Es probable que haya politicas de empresa en relaci6n con la forma que deben adoptar 10s e-mail dirigidos a cornpradores. Por ello deberia existir un bean de sesidn responsable de enviar estos e-rnail. En ocasiones resulta dificil determinar lo que debe ser implementado como bean de sesi6n sin estado y lo que debe ser una clase de ayuda o una funci6n. Hay concesiones bdsicas entre eficiencia de implementaci6n y facilidad de codificaci6n por un lado (para clases ayudantes), y capacidad de reutilizaci6n y gesti6n por otro lado (para sewicios de bean de sesi6n sn estado). Algo que favorece a 10s beans de sesi6n sin estado es que, aunque existen costes asociados a su invocaci6n en comparaci6n con el c6digo Java genirico, son 10s menos costosos de 10s tres tipos de beans. Pueden ubicarse en reserva y reutilizarse de forma eficiente, a diferencia de 10s beans de sesi6n con estado, y no tienen requisitos de persistencia, a diferencia de 10s beans de entidad. En general, si alguna porci6n de funcionalidad fuera itil por si misma para mhltiples clientes, deberia como minimo ser considerada para ascender a sewicio reutilizable. Sin embargo, el mayor grupo posible de funcionalidad deberia ser elegido para su ascenso.

Este capitulo ha presentado 10s Enterprise JavaBeans diseiiados para encapsular bgica de ernpresa y proteger a1 desarrollador de la aplicaci6n de tener que preocuparse de temas de nivel de sistemas. Hernos aprendido lo siguiente sobre 10s EJB:
0 Estdn pensados para sistemas transaccionales 0 Son componentes portatiles, reutilizables, de lado sewidor que se ejecutan en un contenedor 0 Contribuyen a la productividad del desarrollador, amplian la capacidad de la aplicaci6n y mejoran la estabilidaddel sistema 0 Se puede acceder a ellos desde diferentes tipos de clientes 0 Existen cuatro tipos de beans: de sesi6n son estado, de sesi6n sin estado, entidad y controlados por mensajes 0 Existen cuatro partes fundamentales en beans de entidad y de sesi6n: la interfaz bisica, la interfaz remota y/o local, la clase de implementaci6n y el descriptor de despliegue XML; 10s beans controlados por mensaje s61o tienen una clase Java: la clase bean

O El desarrollador de bean de ernpresa debe seguir ciertas reglas para obtener 10s beneficios de la tecnologia EJB

Arquitectura y disefio EIB


O La funci6n de diferentes EJB puede comprenderse analizando un modelo de una empresa en terminos de objetos interfaz, objetos control y objetos entidad
En el pr6ximo capitulo, analizaremos mis detenidamente 10s beans de sesi6n y empezaremos a implementar una versi6n de la aplicaci6n que hemos analizado en este capitulo.

Beans de sesion y Iogica de empresa


La especificacih Enterprise JavaBeans 2.0 ofrece tres modelos diferentes para Enterprise JavaBeans, beans de entidad, beans de sesi6n y beans controlados por mensaje. En este capitulo, analizaremos 10s beans de sesi6n. El bean de sesidn se utiliza para representar flujo de trabajo, Iogica de empresa y estado de aplicaci6n. Este capitulo, abarca 10s siguientes temas exhaustivamente: Las diferencias entre beans de sesi6n con estado y sin estado
0

La funcion de 10s beans de sesion en la implernentacion de 16gica de empresa El uso de beans de sesi6n como fachada Las concesiones para almacenar estado en varios niveles de su diseiio

a a a a

El uso de beans de sesi6n para acceder a almacenamientos persistentes Las retrollamadas y el ciclo de vida de un bean de sesi6n C6mo utilizar una conexi6n JDBC en su c6digo C6mo acceder a variables de entorno

A medida que vayamos analizando las retrollamadas y el ciclo de vida de un bean de sesion, desarrollaremos dos sencillos bean: un bean de sesi6n sin estado y un bean de sesion con estado. Ademis,
seguiremos desarrollando el ejemplo de fabricacibn. En el context0 de esta aplicaci6n, abordaremos algunas tecnicas bisicas de implementation, como devolver al cliente objetos de vista. Sin embargo, esta aplicaci6n hace uso de varios beans de entidad por lo que a h tendremos que esperar para compilar, desplegar y ejecutar estos beans.

Capitulo 15

Beans de sesion y estado


Hay dos tipos de beans de sesion: con estado y sin estado. Estos dos tipos tienen mucho en comun:
O Ambos implementan la interfaz j avax . e j b SessionBean y, por lo tanto, tienen las mismas

retrollamadas de contenedor
O Ambos representan un recurso privado para el cliente que 10s ha creado O Ambos pretenden modelar un proceso o una tarea 0

Ambos pueden actualizar datos compartidos pero no 10s representan del mismo mod0 que un bean de entidad

De hecho, el unico mod0 en que un EJB puede distinguir un bean de sesi6n sin estado de un bean de sesion con estado es examinando el archivo del descriptor XML para encontrar el tip0 de sesion deseado por el programador. La diferencia fundamental entre 10s dos tipos de beans es (como resulta obvio por sus nombres) como tratan el estado de cliente (es decir, sus variables). U n bean de sesidn con estado puede mantener datos entre diferentes accesos de cliente. U n bean de sesidn si estado, no. La sencilla pero importante diferencia tiene complejas ramificaciones para el diseho de su sistema. Nos referiremos a ellas mis adelante pero una regla bisica que debemos tener en mente es que 10s beans de sesion con estado so10 deben utilizarse en la frontera del modelo de objeto. Recuerde la sencilla division de funcionalidad para objetos en el modelo de anilisis. Hay tres tipos fundamentales: objetos interfaz, objetos control y objetos entidad. U n componente EJB que representa un objeto interfaz puede ser implementado como bean de sesi6n con estado o sin estado. U n componente EJB que represente un objeto control invocado desde un componente EJB que represente un objeto interfaz debe ser un bean de sesi6n sin estado. Los objetos entidad del modelo de anilisis no siempre tienen un componente correspondiente en la implementation. Cuando si lo tienen, ese componente debe ser un bean de entidad. Aunque un bean de sesi6n puede actualizar datos compartidos, no puede representar esos datos del mismo mod0 que un bean de entidad.

Representacion de logica de empresa


U n bean de entidad es una entidad completa de datos mientras que un bean de sesion controla la interactuaci6n entre estas entidades y el proceso en su conjunto. Una buena arquitectura para muchos objetivos consiste en organizar estos beans de dos capas. La capa inferior proporciona servicios geniricos, reutilizables, como "liberar pedido de trabajol'o "validar tarjeta de cridito" (la denominaremos capa de servicios). Aqui es donde se implementan 10s objetos control del modelo de anilisis. La capa superior proporciona acceso controlado a estos servicios desde clientes como un sistema MRP (planificaci6n de recursos de fabrication) o un servlet de carro de la compra (la denominaremos capa de control de acceso). Aqui es donde se implementan 10s objetos interfaz del modelo de anilisis. Anteriormente, hemos analizado el motivo de las diferencias entre el modelo de anilisis y la verdadera implementaci6n de la aplicaci6n. Podriamos combinar actividades relacionadas con control, como notificar a un gestor que un comprador se esti acercando a su limite de crkdito, con actividades

Beans de sesion y Iogica de empresa


relacionadas con la interfaz, como proporcionar una interfaz a la funcionalidad de comercio electr6nico en piginas JSP. Obviamente, la divisi6n de trabajo entre estas dos capas no seri perfecta. En general, es mejor pecar por exceso de precauci6n separando 10s componentes reutilizables de su diseiio inicial. Para que esta arquitectura funcione, debe mantenerse una cierta categoria de informaci6n conocida como estado conversacional. El estado conversacional representa informaci6n creada durante un intercambio de solicitudes y respuestas. A medida que progresa el diilogo entre ambos niveles, el estado conversacional acumulari informaci6n significativa sobre el historial del intercambio, permitiendo que posteriores solicitudes hagan referencia a este historial. ~ s t es e un factor de 10s que debe tener en cuenta, si utiliza esta arquitectura. El estado conversacional nunca debe mantenerse en la capa de semicios. Siempre debe mantenerse en la capa de control de acceso, si esti guardado en un EJB. Una implementaci6n de objeto control puede formar parte de un bean de sesi6n con estado si el programador ha combinado un objeto control con un objeto interfaz para simplificar las cosas, per0 el objeto control no debe depender de este estado. U n motivo por el que no es asi es porque reduce la capacidad de reutilizaci6n del objeto control en diferentes contextos. Sin embargo, hay una formulacion mis general de esta regla que prohibe el estado de capa de semicio, basada en criterios especificos de EJB. Si e s t i utilizando beans de sesi6n con estado, nunca deben ser encadenados mediante llamadas mutuas de mitodos de empresa.

EI contenedor EJB tiene la opci6n de descartar el estado despuks de un tiempo muerto considerable. Es decir, puede destruir su bean de sesi6n con estado y generar una excepci6n la pr6xima vez que intenta
invocarlo. Gestionar el estado con mdtiples vencimientos introduce complicaciones necesarias en su diseiio.

Beans de sesion como fachada


Quizis el patr6n de diseiio mis importante surgido hasta ahora en sistemas que utilizan tecnologia Enterprise JavaBeans es el que utiliza un bean de sesi6n para proporcionar una fachada a un cliente. Una fachada es una interfaz de nivel superior para configurar u n grupo de interfaces en u n subsistema y puede ser considerada u n caso m i s general del objeto interfaz de modelo de anilisis analizado anteriormente.

Como puede ver en el diagrama, utilizar un bean de sesi6n para proporcionar una fachada significa que s610 existe un punto de entrada a nuestro sistema. Desde el punto de vista de 10s clientes, s61o hay un bean de sesi6n con el que interactuar, puesto que toda su interacci6n sucede en ese bean, que a su vez pasa sus

Capitulo 15
solicitudes a las otras partes del sistema. Asi, podemos ver que este patr6n es conocido como el patrdn de fachada porque proporciona un frontal (fachada) a nuestro sistema. Existen varias razones generalmente aplicables para utilizar el patr6n de fachada, tales como reducir la complejidad y minimizar dependencias entre subsistemas. Estos motivos han sido analizados con anterioridad y todas estas razones se aplican al caso de 10s EJB. Pero existen varias razones adicionales para proporcionar a un cliente una fachada que sea especifica de sistemas distribuidos y tecnologia Enterprise JavaBeans. Un cliente tipico necesitari acceder a la 16gica de empresa en multiples beans de sesi6n y a la 16gica de validaci6n en multiples beans de entidad. Considere las cuatro siguientes ventajas de utilizar una fachada, en lugar de acceder a 10s beans de sesidn y de entidad directamente desde el cliente: Disminucion del trifico de red El trifico de red siempre ha supuesto una limitaci6n sobre el rendimiento de sistemas de objetos distribuidos. La programaci6n orientada a1 objeto conlleva normalmente numerosas llamadas a metodos que implementan funcionalidad discreta y limitada. Los clisicos ejemplos son 10s mktodos g e t y s e t . Si estas llamadas de metodos tienen lugar de forma remota, todos 10s parimetros y valores de retorno deben ser enviados por la red. Por ejemplo, supongamos que un cliente quiere sumar 10s resultados de invocar g e t P r i c e ( ) en una coleccidn de 100 beans de entidad. Si el cliente ha invocado 10s beans de entidad directamente, cada invocacidn y cada respuesta viajari por la red. Si el cliente ha invocado la fachada del bean de sesidn que ha realizado la suma, s61o es necesario que una invocacidn y una respuesta viajen por la red. Invocando 10s bean de entidad localmente, la fachada de bean de sesidn de nuestro ejemplo ha reducido el trifico de red en dos 6rdenes de magnitud. (Por supuesto, esto presupone que la fachada esti en la misma miquina o en un vinculo de red aislado, con 10s otros beans a 10s que accede.)

Control transaccional declarativo En un tipico sistema de empresa, 10s resultados de multiples operaciones deben aplicarse como una unica unidad. Tome el ejemplo de una transferencia en un sistema bancario. La transferencia conlleva dos operaciones: eliminar dinero de una cuenta y ahadirlo a otra. Si una operaci6n fallara, el banco o el cliente perderian dinero. Si una fachada de bean de sesidn realiza ambas Ilamadas, el contenedor EJB puede gestionar el proceso automiticamente basindose en informaci6n declarativa proporcionada por el desarrollador. Si el cliente realiza ambas llamadas, el cliente es responsable de garantizar que las operaciones son atdmicas; ambas deben tener exit0 o ambas deben fallar.

O Menor n6mero de interposiciones innecesarias Para proporcionar sus servicios a 10s EJB, el contenedor ahade una capa de indireccih entre el cliente y el bean. Esta capa consumiri inevitablemente algunos recursos en el servidor, como tiempo del procesador y espacio de memoria. Si un EJB esti llamando a otro EJB en el mismo contenedor, parte de su trabajo puede ser optimizado (por ejemplo, utilizando interfaces de componente local, que permiten realizar llamadas Java directas entre EJB) y pueden ahorrarse recursos de servidor para la 16gica de empresa. Por ejemplo, el servidor puede evitar algunas comprobaciones de seguridad despues de conseguir superar la primera.

Logica de empresa en el nivel correct0 Si son necesarios multiples beans para proporcionar una funci6n de empresa, normalmente habri a@n orden y relaci6n con estas Ilamadas. Ademis de vincular estrechamente la capa cliente a la implementacibn de la capa de bgica de empresa, realizar estas llamadas desde el cliente significa que una cierta cantidad de flujo de trabajo se localiza en la capa cliente. Utilizando un bean de sesidn como fachada, el cliente ya no esti estrechamente vinculado a la 16gica de empresa y se preserva mis flujo de trabajo en el servidor. El modo habitual de organizar su aplicaci6n es limitar 10s beans de entidad a representar estrictamente filas en su base de datos mientras que un Gnico metodo de empresa en un bean de sesi6n agruparia varias llamadas en uno o varios beans de entidad.

Beans de sesion y Iogica de empresa


En general, todos nuestros accesos a EJB desde aplicaciones de cliente deben sera travks de un reducido nurnero de fachadas de bean de sesi6n. Obviarnente esta regla no se aplica a 10s mismos EJB, que pueden tener beans de sesi6n sin fachada o de entidad corno clientes; de no ser asi, la fachada necesitaria otra fachada y asi indefinidamente. Habri circunstancias que creen excepciones adicionales a esta o a cualquier regla de disefio. Considere detenidamente las desventajas antes de decidir que tiene una de esas excepciones.

El problema del estado conversacional


El estado puede dividirse en dos tipos: transaccional y conversacional.

Aproximadarnente, estado transaccional son 10s datos que almacenamos en el almackn persistente. Multiples clientes pueden leery modificar estos datos sin problema. Si el servidor de aplicaci6n falla o es reiniciado, 10s datos todavia siguen disponibles en el almackn de datos. U n ejemplo seria un pedido realizado por un comprador. Estado conversacional son 10s datos almacenados en :achk en variables de aplicaci6n, en el cliente, en el contenedor EJB o en el servidor de aplicaci6n. Estos son datos privados que no son accesibles para otros clientes. U n ejemplo seria el ornnipresente carro de la compra de un sitio Web. Si el estado conversacional no se convierte en estado transaccional, puede desaparecer cuando desaparezca un componente de la aplicacidn (en el cliente o servidor).

Esta seccidn hace referencia hicamente a1 estado conversacional. El estado conversacional no incluye artefactos de implernentacidn corno conexidn a una base de datos o un socket que sea mantenido a lo largo de la vida del componente, independienternente de las acciones del cliente.

Mantener coherentes 10s datos transaccionales es un problema. Afortunadamente, es un problema en el que la industria informa'tica tiene mucha experiencia en resolver. Las bases de datos relacionales son una tecnologia madura y las tkcnicas para utilizarlas de forma efectiva son bien conocidas. Mientras tanto, el problema del lugar de almacenamiento del estado transaccional (aunque quizas objetivamente ma's facil) es tambikn un problema ma's nuevo, (a1 menos en tkrminos de modernos diserios multinivel) y ma's proclive a provocar un acalorado debate entre diseriadores de aplicaci6n experimentados.
Cualquier aplicacidn que no sea trivial tendri estado conversacional. Dependiendo del cliente, este estado puede ser almacenado de diferentes rnaneras. U n G U I Swing puede obviamente almacenar estado en objetos Java. U n navegador Web puede almacenar estado en el cliente (cookies, carnpos ocultos, reescritura URL, etc.) o en el servidor (sesidn HTTP). El estado que es 16gicamente conversacional puede en realidad ser alrnacenado en una base de datos transaccional o puede simplemente ser almacenado en la mernoria. Los beans de sesidn ofrecen otro espacio en el que puede almacenarse estado. En ciertas circunstancias, esto puede facilitar el desarrollo de la aplicaci6n. El estado puede ser alrnacenado de forrna unificada para multiples tipos de clientes: un cliente Web, un cliente G U I Swingy un Palm Pilot, por ejernplo. La alternativa seria mantener estado mediante tres mktodos diferentes, que quizis no permitan las rnismas capacidades presentes en su servidor de aplicaci6n. Sin embargo, las ventajas potenciales del desarrollo de la aplicacidn deben equilibrarse frente a1 coste de reajustabilidad y rendimiento de la aplicaci6n. Para comprender la concesibn, ayuda entender quk esti ocurriendo detris del escenario con el contenedor EJB.

Capitulo 15

, :
C
I

EJB

EJB

Lbgicamente, todos 10s beans de sesi6n estin asociados uno a uno con una referencia de cliente particular, como muestra el siguiente diagrama. El EJB es creado.cuando el cliente invoca c r e a t e ( ) y destruido cuando el cliente invoca remove ( ) :

EJB

Reserva

Si cinco mil clientes Web utilizan su aplicacibn, habri cinco mil beans de sesi6n en el servidor. Sin embargo, con un bean de sesi6n sin estado, el contenedor tiene la oportunidad de una importante optimizaci6n reservando beans. C o m o no tienen estado, no hay ningtin efecto sobre el bean desde ninguna llamada de cliente, por lo que un bean puede ser reutilizado para mtiltiples clientes: Esto tiene un efecto importante sobre 10s recursos disponibles. En lugar de cinco mil beans de sesi6n sin estado, un contenedor podria tener una reserva de solo cincuenta. Por supuesto, la reserva podria ajustarse dinimicamente para cubrir un nGmero arbitrario de solicitudes para servir.
Una "reserva"es simplemente una coleccidn de instancias que se encuentran disponibles para servir solicitudes. U n servidor concreto podria reservar componentes, hilos, conexiones a bases de datos, conexiones a sockets y muchos otros recursos. Esta reserva es invisible para el desarrollador de componentes, aunque el administrador del servidor puede cambiar su funcionamiento.

Si 10s beans de sesi6n sin estado n o tienen estado, ipor qu6 habrian de tener variables? Los beans de sesi6n sin estado pueden tener estado permanente no asociado a un determinado cliente. Por ejemplo, un bean podria tener un socket abierto a un recurso utilizado por cada cliente. #or qu6 no pueden ser multihilo? Se debe a motivos de disefio, para simplificar el modelo de desarrollo para componentes EJB. Puesto que nunca accede a EJB mis de un hilo a la vez, el programador no necesita preocuparse sobre la sincronizaci6n del acceso a este estado permanente. Igualmente, 10s beans de sesi6n sin estado pueden

Beans de sesion y Iogica de empresa


tener estado asociado a un cliente en una llamada de metodo concreta. Simplemente n o pueden mantener este estado en las llamadas de metodo. Por ejemplo, imagine que el cliente ha invocado el metodo EJB calculateDemand (Product product) Este metodo invoca diez mktodos ayudantes. Como ventaja, el programador podria configurar una variables product o, en lugar de pasar el product o a 10s diez metodos de ayuda. Sin embargo, la prbxima vez que se invoque el bean de sesibn, no puede asumirse nada sobre el valor de la variable product o.

Personalmente, no creo que pueda hacer esto y tener un cddigo bien estructurado. Estas variables de estado m e parecen en gran medida variables globules, variables por las que, por consenso, la industria de desarrollo de software esta en contra desde 10s a6os setenta.
Para ayudar al contenedor EJB a gestionar un gran numero de beans de sesibn con estado, las retrollamadas y reglas han sido incluidas en la especificacion para otorgar al contenedor la capacidad de trasladar a un bean de sesibn con estado a almacenamiento temporal, y restaurarlo desde ese almacen, entre transacciones. El algoritmo que utiliza el contenedor para decidir cuindo almacenar un bean es especifico del contenedor EJB. Almacenar un bean se denomina pasivacibn y su reactivacibn se conoce comoactivacibn. Activacibn y pasivacibn son metodos efectivos deztratar el problema de recursos de servidor limitados. Sin embargo, si es importante para su aplicaci6n la reajustabilidad, la mejor prictica es mantener estado en el cliente y pasarlo de vuelta a1 servidor con cada invocacibn. En el caso de un cliente Java, esto puede en realidad resultar m i s ficil que utilizar un bean de sesibn con estado. En el caso de un cliente Web infradotado, el almacenamiento de estado en el cliente puede resultar dificil, principalmente debido a las variaciones de entornos y permisos en 10s que puede ejecutarse su aplicacibn cliente. Tendri que analizar detenidamente las concesiones de rendimiento, seguridad y productividad de desarrollo.

Beans de sesion y almacenamiento persistente


El resultado final de la lbgica de empresa es a menudo la modificaci6n de datos internos o la adicibn de datos a1 almacenamiento persistente de nuestra empresa. La especificaci6n Enterprise JavaBeans proporciona beans de entidad para representar estos datos y proveer servicios persistentes. Sin embargo, es posible evitar 10s beans de entidad y acceder a un almacenamiento de datos persistente (como una base de datos) directamente desde nuestros beans de sesibn. Es decir, nuestros beans de sesibn serin responsables de la funcionalidad representada por objetos entidad en nuestro modelo de anilisis. A medida que vamos evitando muchos de 10s servicios de persistencia del contenedor, se afiadiri normalmente complejidad a nuestro esfuerzo de desarrollo. Si estamos utilizando una base de objeto o una herramienta de asociacibn objeto-relacional, esto no se aplica y quizis el enfoque apropiado sea un bean de sesibn puro. En ciertas circunstancias, podemos aumentar nuestro rendimiento codificando el acceso direct0 a datos a traves de JDBC y beans de sesion en lugar de utilizar beans de entidad.

En otras circunstancias, u n enfoque puro de bean de sesidn tendria un efecto perjudicial en el rendimiento porque terminarias implementando muchos servicios complejos que 10s desarrolladores de servidores de apficaci6n ya ban optimizado por nosotros, como resewas de hilos de conexiones, preactivacidn de beans, etc. Determinar que' caso aplicar en nuestra situacidn conllevara' considerar estrategias de bloqueo de bases de datos, patrones de acceso a datos en nuestra apficacidn, la impfementacidn de nuestro contenedor EJB y requisitos de nivel de aislamiento. Antes de perfilar diferentes arquitecturas, plantbese cua'nto necesita escalar en realidad. La mayoria no trabaj para una compa6ia abrea o para Hacienda. Las situaciones m i s comunes requeriran el uso de beans de entidad con persistencia gestionada por contenedor para operaciones sobre entidades individuales y grupos reducidos. Los beans de sesio'n sera'n un vehiculo apropiado para operaciones sobre un conjunto de datos ( u n ca'lculo, una suma o una lista).

Capitulo 15
Si construimos nuestro sistema utilizando solo beans de sesi6n sin estado, estaremos utilizando una de las arquitecturas mis antiguas para grandes sistemas. El mayor sistema fue construido utilizando monitores de Procesamiento de Transaction (TP). Estos monitores T P desempeiiaban la misma funcion que desempeiia hoy en dia un contenedor EJB. En lugar de un metodo bean, el programador de la aplicaci6n escribiria un programa que pudiera tomar parimetros de arranque. El programa cliente realizaria una llamada a1 monitor TP, que ejecutaria el programa con 10s parimetros del cliente. Se mantendria todo el estado en la base de datos. Esta arquitectura puede funcionar con sistemas transaccionales de grandes dimensiones que no tienen - requisitos de almacenamiento en cache mis a116 de 10s proporcionados por la base de datos.

La especificaci6n Enterprise JavaBeans 1.0 convirtio en opcional la ~om~atibilidad con beans de entidad; se esperaba que 10s desarrolladores que utilizaran un contenedor sin apoyo para beans de entidad codificaran el acceso direct0 a la base de datos en beans de sesi6n a travks de algun tip0 de herramienta. Aunque la version 1.1 convirti6 en obligatorio la compatibilidad con beans de Entidad desde el contenedor, depender exclusivamente de beans de sesi6n sigue siendo una opci6n vilida. La especificaci6n EJB 2.0 introduce mejoras radicales en 10s beans de entidad, de mod0 que la decisi6n de no utilizarlas debe tomarse de forma ponderada.

Bean calculadora de asistencia financiera


Los componentes EJB tienen metodos de retrollamada a traves de 10s cuales el contenedor les proporciona notificaciones sobre su ciclo de vida (cuando estin a punto de ser creados, destruidos, almacenados en un almackn persistente o recuperados desde un almacen persistente). Estos metodos de retrollamada estin definidos para cada tip0 de bean (sesion, entidad, controlados por mensaje) en interfaces del paquete j a v a x . e jb. Ambos beans de sesi6n (con estado y sin estado) tienen 10s mismos mktodos de retrollamada porque ambos deben implementar j a v a x . e jb .s e s s i o n B e a n . Sin embargo, estos metodos de retrollamada son utilizados de forma diferentes, ya que 10s beans de sesi6n con estado y sin estado tienen diferentes ciclos de vida dentro del contenedor. Vamos a examinar las diferencias de uso y de ciclo de vida entre 10s beans de sesion con estado y 10s beans de sesi6n sin estado, implementado dos veces la misma funcionalidad. Despuks la implementaremos una tercera vez, mostrando c6mo pueden cooperar beans de sesi6n con estado y sin estado (uno en la capa de control de acceso y otro en la capa de servicios). La aplicacion que vamos a escribir calculari la asistencia financiera que requeriri un estudiante para asistir a la universidad, aplicando una f6rmula que tiene en cuenta 10s costes universitarios y 10s recursos familiares.

Si es usted administradorpara la universidad en lugar de programador Java, debe saber que he inventado esta fo'rmula y que no debe aplicarla a sus estudiantes.
En primer lugar, permitame describir la f6rmula que utilizaremos. Nuestro cilculo final seri que las necesidades del estudiante son equivalentes a1 coste de 10s estudios universitarios menos la suma de la contribucion de sus padres y sus ganancias de verano. Nuestra aplicaci6n cliente nos imprimiri estos datos, junto con el nombre del solicitante (de mod0 que no se sientan tan infelices con un ma1 resultado). La f6rmula tiene varios pasos intermedios. El coste de la universidad se calcula como la suma de tres numeros: matricula y tasas; alojamiento y pensi6n; y libros y material. La contribucion de 10s padres se calcula como la suma de tres cantidades: un porcentaje de 10s ingresos del padre 1; un porcentaje de 10s ingresos del padre 2; y un porcentaje de sus bienes. El porcentaje de bienes disponibles tambikn se calcula utilizando tres numeros: el valor de sus bienes liquidos; el valor de su residencia; y el valor de sus otros bienes. Obviamente, alguien que sea bueno en matemiticas podria presentar todos estos pasos en una formula pero, para mayor simplicidad, implementaremos esta f6rmula en tres pasos distintos en nuestro bean de sesion.

Beans de sesion y logica de empresa

Bean calculadora de necesidad financiera sin estado


Comencemos por la versidn de bean de sesidn sin estado. Recuerde que hay cuatro partes bisicas para un componentes EJB: su interfaz remota, su interfaz inicial, su clase de implementacidn y su descriptor de implementacidn. Primero, definiremos nuestra interfaz remota.

La interfaz remota de calculadora de necesidad financiera


Proporciona a1 cliente acceso a la funcionalidad de empresa del EJB. A1 igual que toda interfaz remota en Java, cada metodo debe declarar que genera una excepcidn j a v a .rrni .R e m o t e E x c e p t ion.Esta interfaz ~ ect: debe amp liar^ J B O j
package finCalc.stateless;

iimport j avax. ejb.EJB0bject; public ir~terface F i n a r ~ c i a l N e e d C a l r u l a t o r extends EJBObject


{

public double calculateNeed(doub1e attendancecost, d o u b l e parentsContribution, double studentSummerWork) throws java.rml.RemoteExceptior~; publlc double calculateAttendanceCost double tuitior~Ar~dFees, d o u b l e bscksAndSupplies, double r o ~ m A n d B o a r d ) throws -J a.Ja.rrnl. RemoteException;
(

or~( pareritlc'ontribution, public double c a l c u l a t e P a r e r ~ t s C o r ~ t r i b ~ u t idbuble double parent2Contribution, double g r v ~ u p C o r ~ t r i b u t i o r ~ ) throws j ava. rmi. RernoteEzceptior~;

public double c a l c u ? a t e P a r e n t C o r ~ t r i b u t i o n ( d o u b l e income) t h r ~ w s java.rmi.RemoteException; public dollble c a l c u l a t e G r o u p ~ o r ~ t r i b u t i o n ( d o u b lliquidAssets, e d o u b l e primaryHomeValue, double o t h e r A s s e t s ) throws ja'~a. rrni .RemoteException; public Strir~g getMessaqe(Strir1g applicant, double n e e d ) throws java.rrni.RemoteExceptisn;

1 Puesto que nuestro bean de sesidn n o tiene estado, debemos pasar en ambas direcciones 10s datos de estado de la aplicacidn entre el cliente y el servidor.

El cliente de necesidad financiera


El resultado de cada cilculo intermedio debe ser devuelto a1 cliente desde el servidor y despues pasado de vuelta a1 servidor desde el cliente cuando se precise para un paso posterior. Para ilustrar este punto, este es el cliente que utilizaremos:
package fir~Calc.stateless;

import java.util.Properties;

Capitulo 15
import import public j a v a x . r ~ a r n i n gC . ontext; j avax. naming. I n i t i a l C o r ~ t e x t ; class Probar Testclient dates rnain(Strir,g[] args)
( (

//

public try

s t a t i c void

i
P r o p e r t i e s prop
=

new

Properties ( ) ;

prop.put(Cor~text.INITIALCONTEXT FACTORY, prop.put(Context.PR0VIDER


Context Object ctx
=

" w e b l o g i c . j n d i . W L I n i t i a l C o r ~ t e x t F a c t o r y " ); URL, " t 3 : / / l o c a l h o s t : 7 0 0 1 " ) ; new


=

I r i i t i a l C o r ~ t e x( tp r o p ) ;

objref

c t z . lookup ( " S t a t e l e s s F i r ~ a r ~ c i a l N e e d C a l c u l a t o r ;" )


=

FinancialNeedCalculatorHome home

( F i n a n c ialNeedCalculatorHorne) j a v a x . rmi. P o r t a b l e R e m o t e O b j e c t n a r r o w ( o D jr e f , F i n a r ~ c i a l N e e d C a l c u l a t o r H o r n e . c l a s s ; )

Finar~cialNeedCalculator calculator

home.create ( 1 ;

double attendanceCost = calculator. calculateAtter~dar,ceCos( t 30000.0,

500.0,

2000.0) ;

double parent1 = calculator. calculateParer~tCor~tributio (-S5OOO.O) r~ ; double parent2 = calculator. calculateParer~tCc?r~trib~ut (i 3o 5r0 ~ 00.0); double group
=

calculator.calculateGrc?upCor~tributior ( ~ 10000.0, 150000. 0, 6000.0) ;

double parentsContribution = c a l c u l a t o r . c a L c u l a t e P a r e r ~ t s C o r ~ t r i b u t i o(rp a r e n t l , double need


=

parent2,

group) ;

calculator. calculateNeed (atter~dar~ceCost, parentsContribution, 2500.0); need) ) ;

Systern.olut . p r i n t l n ( c a l c u 1 ~ a t o r . g e t M e s s a g e ("Daniel",

catch (Exception e ) { e.printStackTrace ();

Podemos ver que el cliente debe guardar 10s resultados de pasos intermedios como calculateParentContribution ( ) parasu uso en posteriores pasos como calculateParentsContribut ion ( ) .Avancemos haciael resto del bean antes de analizarel c6digo.

Beans de sesion y Iogica de empresa


La interfaz iniciai calculadora de necesidad financiera
La interfaz inicial es la segunda parte bisica para un componente EJB. Esta interfaz otorga acceso a1 programador a la funcionalidad de ciclo de vida como la creaci6n y destrucci6n del componente. Podemos observar su uso en el cliente de prueba. El programador que crea un bean de sesion so10 necesita preocuparse por declarar mttodos " c r e a t e " en la interfaz inicial. Para el escritor de un bean de sesi6n sin estado, s61o puede existir un mCtodo c r e a t e ( ) sin parimetros. El motivo para ello debe resultar obvio: si el EJB no tiene estado, iquC importari si le otorga un parimetro cuando lo cree? Lo habri "olvidado" para cuando se produzca la primera llamada de mttodo de empresa.

La interfaz inicial para un bean de sesi6n sin estado es la parte mis aburrida de c6digo del rnundo, ya que siempre adopts esta forma (~610 cambia el nombre del paquete, el nombre de la interfaz y el valor de retorno del mttodo c r e a t e ( ) ):
package import finCalc.stateless; j a v a x . e j b . EJBHome;

p u b l i c i n t e r f a c e F i r ~ a r l c i a l N e e d C a l c u l a t o r H o m e e x t e n d s EJBHome { F i n a n c i a l N e e d C a l c u l a t o r c r e a t e ( ) t h r o w s j a v a . rmi . R e m o t e E x c e p t i o n , javax. ejb.CreateExceptior1;

La ciase de impiementacion de la caicuiadora de necesidad financiera


La clase de implementaci6n es la tercera parte bisica para un componente EJB. Tiene mCtodos de retrollamada de contenedor y mCtodos de implementacidn de 16gica de empresa. Para un bean de sesi6n, debe implementar la interfaz j a v a x . e j b .s e s s i o n B e a n , que le proporciona una plantilla de m6todos de retrollamada que requiere el contenedor. Adembs, el desarrollador de EJB debe afiadir un mCtodo e j b C r e a t e ( ) para cada mttodo c r e a t e ( ) en la interfaz inicial, con parimetros coincidentes y un tip0 de retorno de v o i d . Por supuesto, para un bean de sesi6n sin estado existiri uno sin parimetros. Esta es la clase de nuestro bean calculadora de necesidad financiera:
package import import public finCalc.stateless; j avax. e jb. SessionBean; j avax. e j b . S e s s i o n C o r ~ t e x t ; class

FinancialNeedCalculatorEJB i m p l e m e n t s

Sessic~nBean {

/ / Mktodos d e c i c l o d e v i d a public void ejbActivate() { 1


public void e jbpassivate ( )
{ ]

public public

void void

e jbCreate ( 1

i1
ctx)
{

setSessionContext ( SessionContext

//

Metodos d e empresa public double calculateNeed(doub1e attendanceCost, double parentsContribution, d o u b l e studentSummerWorh) { d o u b l e need = a t t e n d a n c e C o s t - ( p a r e r ~ t s C o n t r i b u t i m

Capitulo 15
+
return ( r ~ e e dc 0.0)
?

studentSurnrnerWork) ;

0.0

: need;

I
public double

return

calculateAtterldarlceCost (double tuitior~AridFees, d o u b l e booksArldSupplies, d o u b l e roornAndBoard) ( t u i t i o r 1 A r 1 3 F e e s + b o o k s A r ~ d S u p p 1 i e . s + roornAr,dBoard;

1
public double calculateParer~tsCor~tributio (d ro ~uble p a r e n t l C o r ~ t r i b u t i o r ~ , double parent2Contributior,, d o u b l e g r o u p C o r ~ t r i b u t i o r ~ {) parentlContribution + parent2Contribution + groupContribution;

return
I

public double ca1culateParentContributior~ (double income) r e t u r n (incnrne * 0 . 2 ) ;

I
public dnuble

return

calculateGroupCor1tributior1(doub1e liquidAssets, d o u b l e prirnaryHorneValue, double otherAssets) { ( 1 i q u i d A s s e t s * 0 . 3 ) + (prirnaryHomeValue * 0 . 0 5 ) + (otherAssets * 0.075);

plublic S t r i r q g e t M e s s a g e ( S t r i n g a p p l i c a n t , d o u b l e need) r e t u r r t " D e a r " + a p p l i c a n t + ", y o u r n e e d h a s b e e n c a l c u l a t e d a t " + need +

".";

I
I

Lo primer0 que observari en 10s metodos de ciclo de vida y de sistema es que estin vacios. El programador de 16gica de empresa, en el caso predeterminado, no necesita hacer nada. El contenedor hari todo el trabajo pesado. Examinimoslos de forma individual.
public void ejbCreate0

En un bean de sesi6n sin estado, el mitodo e j bcreate ( ) no seri invocado necesariarnente por el cliente en correspondencia con una llamada a1 rnetodo create ( ) de la interfaz inicial del bean. Debe pensar en e j bCreate ( ) como en un constructor, para inicializar el bean con recursos que puedan ser utilizados por cualquier cliente. (Los recursos especificos de cliente n o son relevantes para un bean de sesi6n sin estado.) si queremos. En un constructor Podemos definir nuestro propio metodo sin argument0 e j bCreate 0 , de este tipo, sin embargo, no podemos acceder a ninguno de 10s siguientes elementos:

Entorno (que normalmente estaria dis~onible en el irbol J N D I bajo " j ava : comp . / e n v W )
O

Gestores de recursos (como una conexi6n JDBC)

0 Otros EJB (el metodo e j bcreate ( ) se ejecuta con un context0 de transacci6n n o especificado)

N o debe definir u n constructor con argumentos; si lo hace, nunca sera' invocado. El ciclo de vida de su EJB esta' controlado por el contenedor y siempre utilizara' el constructor sin argumentos. Si se empefia en definir u n constructor con argumentos, tambie'n debe definir uno sin argumentos. Por el

Beans de sesion y Iogica de empresa


contrario, el contenedor no podra' instanciar su bean. La especificacidn asigna este comportamiento porque debe realizarse en uno de 10s me'todos de ciclo de vida y por ello no hay motivo para aiiadir complejidad a1 proceso de configuracidn y permitir la invocacidn de u n constructor diferente.
public void ejbActivate0 public void ejbpassivateo
El contenedor nunca pasiviza (y, por lo tanto, nunca activa) un bean de sesi6n sin estado y estos dos rnitodos de retrollarnada consecuenternente nunca serin invocados. Necesitan ser irnplernentados porque son utilizados para beans de sesi6n con estado y asi son declarados en la interfaz S e s s i o n B e a n .

public void ejbRemove0


El m i t o d o e j bRemove ( ) es invocado por el contenedor antes de que elirnine sus referencias a1 cornponente y perrnita la recuperaci6n de su rnernoria. Cualquier recurso que fuera asignado a e j b C r e a t e ( ) deberia ser desvinculado aqui.

Observe que el programador de EJB no debe definir un me'todo f i n a 1i z e () para desvincular recursos. Adema's de ser una mala pra'ctica de programacidn en general (no existen garantias sobre ddnde serd invocado el me'todo f i n a 1i z e () o si sera' invocado), tambie'n queda especz$camente prohibido por la especificacidn Enterprise JavaBeans. La mayor parte de estos recursos son habitualmente liberados por la J V M o por el sistema operativo despue's de u n cierto tiempo. Para datos persistentes, u n mod0 de limpiar estos recursos asignados seria examinarlos periddicamente en busca de informacidn obsoleta.
public void setSessionContext(SeorionContext d x )
Si el prograrnador quiere utilizar el contexto de sesi6n en cualquier mitodo de ernpresa, debe guardar una referencia a 61 cuando el contenedor invoque s e t s e s s i o n c o n t e x t ( ) . El contenedor invocara este metodo justo antes de e j b c r e a t e ( ) , de rnodo que el prograrnador pueda acceder a 61 en el metodo e j b c r e a t e ( ) silodesea. El contexto de sesi6n proporciona 10s siguientes rnitodos a1 prograrnador del bean: El metodo g e t E J B O b j e c t ( ) devuelve la interfaz rernota del bean de sesi6n. El metodo g e t E JBHome ( ) devuelve la interfaz inicial del bean de sesi6n.

Elrnet~do~et~aller~rinci () p devuelvelaclasej al ava. s e c u r i t y . Principalque identifica el invocador del objeto EJB de la instancia del bean.
El metodo i s C a l l e r I n R o l e ( ) cornprueba si el invocador de la instancia del bean de sesi6n desernpeiia una funci6n particular. Por ejernplo, ciertas operaciones pueden necesitar la identidad del usuario para ser carnbiadas por las de otro. Este metodo le indicari con exactitud quien esti invocando su m i t o d o de rnodo que pueda actuar consecuenternente. El rnitodo s e t R o l l b a c k O n l y ( ) perrnite a la instancia rnarcar la transacci6n actual de modo que el resultado de la misrna se deshaga. Solo pueden utilizar este metodo las instancias de un bean de sesion con una dernarcaci6n de transaccion gestionada por contenedor. (Este es el caso habitual.) El metodo g e t R o l l b a c k O n l y ( ) perrnite a la instancia cornprobar si la transacci6n actual ha sido rnarcada para ser deshecha. S61o las instancias de un bean de sesi6n con dernarcaci6n de transaccion gestionada por contenedor pueden utilizar este metodo. (Este es el caso habitual.)

O El m C t o d o g e t ~ s e r ~ r a n s a c t i o () n devuelvelainterfaz j a v a x .T r a n s a c t i o n . U s e r T r a n s a c t i o n . Lainstanciapuedeutilizar esta interfaz para demarcar transacciones y obtener estados de transacci6n. S61o las instancias de un bean de sesi6n con demarcaci6n de transacci6n gestionada por bean pueden utilizar este metodo. En general, debe permitir que el contenedor gestione sus transacciones.
Si el programador quisiera acceder a cualquier de estas funcionalidades, escribiria c6digo que se pareciera a1 siguiente:
~f (ctx.isCallerInRole ("adrnir~istrator") { / / ha: a l g a 6 t l l

I
//
o no h a g a s nada

Observe que el context0 de sesi6n no debe ser almacenado en una variable transitoria. Esto es aside mod0 que la referencia n o se perderi durante la pasivaci6n. (La regla probablemente deberia ser seguida con beans de sesi6n sin estado, aunque n o fueran pasivados.) Estos mCtodos de retrollamada son utilizados por el contenedor en puntos bien definidos en el ciclo de vida del bean de sesi6n. El siguiente diagrama quizis le ayude a conceptualizar el proceso:

El contenedor necesta un nuevo bean de ses~on para su reserva

lnstanc~a creada ut~l~zando el constructor sln argumentos

' I
Metodo SetSess~onContext ~nvocado

Metodo ejbcreate

mvocado

ejbRemoved mvocado

Beans de sesion y Iogica de empresa


Observe que 10s metodos e j b c r e a t e ( ) y s e t S e s s i o n ~ o n t e x (t ) no estin correlacionados con ningun uso del componente de ningGn cliente concreto. El contenedor decide cuindo necesita una nueva instancia. Esto puede o no ser provocado por una llamada de metodo de empresa de un cliente. Si el contenedor quiere disminuir el tamafio de la reserva, invocari e j bRemove ( ) sobre una de las instancias y entonces la eliminari de la reserva activa. Formalmente, se denomina transici6n desde el estado me'todopreparado a1 estado no-existe.

El descriptor de implernentacion
La d t i m a parte bisica de un componente EJB es su descriptor de implementaci6n. Normalmente, lo creari con una herramienta (aunque modificarlo manualmente no resulta dificil). Este es el descriptor de implementaci6n de nuestra calculadora de necesidad financiera (en su forma reducida):
<!DOCTYPE e j b - j a r PIJBLIC " - / / S u n Mlcrasystems, I n c . //DTD Erlterprise JavaBeans

2 . O//ENT'

"http://java.sur~.com/dtd/ejb-jar 2 O . d t d n ?
<ejb-jar> cer~terprise-beans> <8ess10rt>

<ejb-name>StatelessFinar~cialculator</ej b-name> < h o m e ? f i r ~ C a l cs .t a t e l e s s . Fir~ar~cialNeedCalculatorHome</horne? <remote?f inCalc. s t a t e l e s s . Fir1ar~cia1EJeedCalculator</remote? < e jb - c l a s s ? f i n C a l c . s t a t e l e s s . F i r 1 a r 1 c i a l E J e e d C a l c u l a t o r E J B < / e ] b - c l a s s > <session-type>Stateless</sessior~-type? <transaction-type?Cor~tair~er</trar~sactior~-rype> </session> </enterprise-beans>

Finalmente, necesitamos otorgar un nombre J N D I a1 inicio del bean. Y esto se consigue utilizando el siguienteweblogic-e j b - j a r . xml:
< ! DOCTYPE

w e b l o g i c - e j b-] a r PUBLIC ' - / / B E A Systems,

I n c . //DTD

WebLogic

6.0.0

EJB//EN1

\http://www.bea.com/servers/wls600/dtd/weblogic-ejb-jar.dtd'?
<weblogic-ej b-j a r ? <weblogic-enterprise-bean>

<ejb-name>StatelessFir~ar~cialculator</ejb-r~ame>
< jn d i - n a r n e > S t a t e l e s s F i n a n c i a l l . l e e d C a l c u l a t n r < / j ndi-name> </weblogic-enterprise-bean> </weblogic-ej b-j a r ?

Ahora podemos ejecutar este ejemplo. Cree un archivo JAR con sus archivos de clase y descriptor de implementaci6n en 10s siguientes directorios:

w e b 1 o g i ~ - e j b - ja r . x r n l ejb-jar.xmi finCalc/ stateless/ F i r ~ a r ~ c i a l N e e d C a l c ~ ~ i. < at ;l odrs s F i r 1 a n ~ i a l N e e d T a l ~ ~ ~ l a t o r Hc o lm as es . FinancialNeedCalculatorEJB. c l a s s

Despliegue este JAR en el servidor de su aplicaci6n. Si esta utilizando WebLogic Server 6.0, simplemente siltuklo en el ~ ~ ~ ~ C ~ O ~ ~ O % W E B L O G I C /config/mydomain/applications -HOME% /.Configure laruta de clase de su cliente s e g ~ n 10s requisitos del servidor de su aplicaci6n. Para este ejemplo, hemos utilizado WebLogic 6.1; tambikn hemos copiado el a r c h i v ~ w e b l o ~. ijar c desde el directorio / b i n de WebLogic el directorio desde donde invocamos T e s t c l i e n t :
java -classpath

.; w e b l o g i ~ zj .ar

finCalc.stateless.TestTlier~t

Debe obtener este resultado:


Dear Daniel,
YOUL

need

has

been

calculateri

at

1050.0.

Bean calculadores de necesidad financiera


Desarrollemos ahora otra versi6n de este componente EJB, como un bean de sesi6n con estado. La principal diferencia entre beans de sesi6n con estado y sin estado radica en que un bean de sesi6n con estado puede almacenar estado de aplicaci6n entre llamadas de mktodo, mientras que un bean sin estado n o puede. En nuestra versi6n del bean, aprovecharemos esta capacidad almacenando todos 10s parametros de entrada entre llamadas y calculando despuks el resultado a la vez.

La interfaz remota de necesidad financiera con estado


~ s t es a la nueva interfaz remota:
package import public fir~Caic.stateful;
j avax. ejb.EJBObj e c t ;

interface void

Fin3ncialNeedCalculator

extends

EJBObject

public

s e t S t u d e n t S ~ ~ m r n e r W o r k i d o ~ ~sb t ll~ ed e n t S u m r n e r W o r l : ) t h r o w s java.rrni.RemoteException;


setAttendanceCosts (double tuitionArdFees, d o u b l e booksAndSupp1 i e s , d o u b l e roomAndBoard) t h r o w s j a v a . r m i . RernoteException; s e t ParentIncome ( d o u b l e income) throws j ava. r m i .RernoteException,

public

void

public

void

TooManyParentsEzception;

public

void

setGroupAssets idol~bleliquidAssets, d o u b l e prirnaryHomeValue, double otherAssets) t h r o w s j a v a . r m i . RernoteException;

Beans de sesion y Iogica de empresa


public
\

String

getMessaqe ( )

throws

j a v a . rrni. R e r n o t e E x c e p t i o n ;

El metodo s e t p a r e n t I n c o m e

()

puede ser invocado dos veces. H e introducido una nueva clase en este

e j e m p l o , ~ o o ~ a n y ~ a r e n t s ~ x c e p tpara i o n ser , utilizada en caso de que el metodo s e t p a r e n t I n c o m e ( ) se invoque por tercera vez:

p u b l i c c l a s s T r ~ o M a n y P a r e r l t s E x c e p t i o n extend..: p u b l i c Toc,ManyParerttsExceptinn( { I
1

Exceptiorl

La interfaz inicial calculadora de necesidad financiera con estado


Una interfaz inicial de bean de sesidn con estado puede ser ligeramente mas interesante que una interfaz inicial de bean de sesi6n sin estado, ya que puede haber multiples metodos c r e a t e ( ) con diversas firmas. Tiene sentido la posibilidad de pasar informaci6n a metodos c r e a t e ( ) de beans de sesidn con estado, porque un bean de sesi6n con estado puede "recordar" qu6 cliente 10s dijo durante posteriores llamadas de metodo de empresa. Esta es la interfaz inicial de la calculadora, que toma el nombre del solicitante como parametro (que sera utilizado en el formato del mensaje):
package
f inCalc. s t a t e f u l ;

i m p ~ z r t j a v a x . e j b . EJBHome;

FinancialNeedCalculator create (Strir,g applicant) t h r o w s j a v a . rrni . R e m e t e E : < c e p t i ~ r t , j a v a x . e j b . C r e a t e E x c e p t i o n ;

La clase de implernentacion de la siguiente calculadora financiera con estado


Observe c6mo la clase de implementaci6n del bean de sesi6n con estado ha tomado el "flujo de trabajo" que estaba localizado en el cliente en el ejemplo del bean de sesi6n sin estado. El metodo g e t M e s s a g e ( ) es casi idtndico a1 cliente:
package import import public finCalc. stateful;
j avax. e j b. SessiunBean; javaz.ejh. SessionCor~text;

class

Financiall.leedCalculatorEJB

implemer~ts SessionBean

String applicant; d o u b l e studentSurnmerWork; double tuitionAndFres; double booksAndSupplies; doub? e roornAr~dBoard; double parentlIncorne; boolean p a r e r ~ t l s e t ; double parent2Incorne; boolean parent2Set;

Capitulo 15

double double double public public pubiic

1iquidAssets; primaryHomeValue; otherAssets; void void void ejhActivate i ) ejbpassivate i ) ejbRemove ( )


{!
{

{ )

1}

public void ejbc'reate (String applicant t h i s , applicant = applicant; parer~tlset= false; parent2Set = false;

1
p u b l i c v o i d setStudentSummerWork(doub1e s t u d e n t S u m m e r W o r k ) t h i s . studentSummerWork = studentSummerWork;
[

I
public
s e t A t t e n d a r ~ c e C o s t s ( d o u b 1 et u i t i o n A n d F e e s , d o u b l e bo,>k s A n d S u p p l i e s , d o u b l e roomAndBoard) 1 t h i s . tuitionAndFees = tuitionAndFees; t h i s . booksAr~dSupplies = booksAr~dSupplies; t h i s . roomAndBoard = roomAndBoard;

void

I
public s e t P a r e n t I n c o m e ( d o u h l e irlcome) throws TooManyParentsException i f (parent2Set) { t h r o w new T o ~ : M a n y P a r e r i t s E x c e p t i o r ~ ( ) ; ] else i f (parentlSet) { t h i s .parent2Income = income; this.parerlt2Set = true; 1 else { t h i s . p a r e n t l l n c o m e = income; this.parentlSet = true; void
{

1
i

public

setGroupAssets (double liquidAssets, d o u b l e primaryHomeValue, double otherAssets) { t h i s . l i q u i d A s s e t s = 1iquidAsset.s; this.primaryHomeVa1ue = primaryHomeValue; this.otherAssets = otherAssets;

void

\
p u b l i c S t r i n g qetMessage i ) [ d o u b l e a t t e n d a n c e c ' o s t = t h i s . c a l c u l a t e A t t e n d a r ~ c e C o s( tt u i t i o r ~ A r ~ d F e e s , booksAr~dSupplies, r o o m A r ~ 3 B o a r d; ) double di3uble double parent1 parent2 group
=

=
=

this. calculateParentCorttributior~ ( p a r e n t l I n c o m e ); t h i s . c a l c u l a t e P a r e n t C o r ~ t r i b u t i o( rp ~a r e n t 2 I n c o m e ) ;

t h i s . c a c u 1 a t e C ; r o u p C o r ~ t r i b u t i o r(~ liquidAssets, primaryHomeValue, otherAssets);

Beans de sesion y Iogica de empresa

double

parer~tsCorltribution

this.calculateParentsCor~tribution (parerjtl, parent2,


double need
=

group);

t h i s . calculateNeed (atter~danceCost, paIentsContributior~, studentSummerWork); need) ;

return

this.getMessage (applicant,

i
public void s e t S e s s i o n C o n t e x t (Sessior1Cor1text c t x ) java.rml.RemoteException throws javax.e]b.EJBException,

(1

private

calculateNeed (double attendancecost, double parerltscontribution, d o u b l e studentSurnrnerWork) 1 d o u b l e need = a t t e n d a n c e c o s t - ( p a r e n t s C o n t r i b u t i o n + studentSummerWork) ; r e t u r n ( n e e d < 0 . 0 ) ? 0.0 : need; double

private

double

return

c a l c u l a t e A t t e r ~ d a n c e C o s( td o u b l e t u i t i o n A n d F e e s , double booksAndSupplies, d o u b l e roomAndBoard 1 1 t u i t i o n A n d F e e s + b o o k s A n d S u p p l i e s + roomAndBoard;

1
private double

calculateParentsContributior~(doub1e p a r e n t l C o n t r i b u t i o n ,
double parent2Contribution, double groupContribution)

1
return parentlContribution

parent2Contribution

groupContrlbutlon;

I
p r i v a t e d o u b l e calculateParentContributior1(doub1e i n c o m e ) r e t u r n (income 0.2);
+

private

double

caculateGroupContributior1(doub1e l i q u i d A s s e t s ,
0.3)

return

(1iquidAssets

d o u b l e prirnaryHomeValue, double otherAssets) 1 (primaryHomeValue 0.05) (otherAssets 0.075);


+ +

1
p r i v a t e S t r i n g getMessageiString applicant, double need) r e t u r n "Dear " + a p p l i c a n t + ", y o u r n e e d h a s b e e n c a l c u l a t e d a t " + n e e d +
{

".";

I
Excepto el metodo c r e a t e ( ) analizado anteriormente, 10s mitodos de ciclo de vida (ej b A c t i v a t e ( ) , e j b p a s s i v a t e 0, ejbRemove ( ) ysetSessionContext 0 ) deestebeanestinvacios,comolo estaban para el bean de sesi6n sin estado. La principal diferencia esti en que ej b A c t i v a t e ( ) y e j h p a s s i v a t e ( ) podrian ser invocados en realidad, dependiendo de la configuracih del contenedor y de la utilizaci6n de recursos. Antes de que un bean sea cambiado a almacenamiento temporal, el contenedor invocari e j b p a s s i v a t e ( ) . Antes de que el bean sea recreado desde ese almackn, el contenedor invocari e j b A c t i v a t e 0.

Capitulo 15
iPor quk son importantes estos mktodos de retrollamada? Si el programador de bean ha adquirido y guardado un recurso que no ha podido ser pasivizado (una base de datos o una conexion de socket), necesitaria liberarlo en e j bpassivate ( ) y volver a obtenerlo en e jbActivate ( ) . Mis formalmente, el desarrollador de bean debe garantizar que dos hechos son ciertos antes de devolver ejbpassivate ( ) :

o Los objetos asignados a 10s campos no transitorios del bean deben estar preparados para su serialization. Deben ser nulos, un objeto serializable o un objeto relacionado con EJB que
manejari el contenedor. Estos objetos especiales relacionados con EJB incluyen interfaces remotas, interfaces iniciales, objetos sessioncontext,una referencia a1 entorno que nombra el context0 o a cualquiera de sus subcontextos o una referencia a un objeto UserTransaction. A menudo, esto sera cierto sin ninguna accion en e jbpassivate ( ) .
0 El desarrollador de bean debe cerrar cualquier recurso abierto, como sockets y cursores de base de datos. Habitualmente, un bean no mantendri recursos abiertos; en su lugar, 10s obtendri del contenedor segGn 10s vaya necesitando. ?El punto fundamental? Normalmente, e j bPas s ivat e ( ) quedari vacio y el contenedor procesari 10s detalles.

Lo mismo sucede con la retrollamada e j bActivate ( ) . Existe para dar a1 programador la oportunidad de volver a obtener cualquier recurso que esti cerrado durante e j bpassivate ( ) . Habitualmente, este mktodo queda vacio. Una advertencia: si hemos establecido que el contenedor no puede arreglirselas durante la pasivacidn y activaci6n (como un objeto no serializable almacenado en una variable no transitoria), el contenedor tiene libertad para ignorar esta parte de su EJB cuando lo pasivice. Compare este diagrama con el anterior para un bean de sesi6n sin estado:

No exlste bean de seaon,

I
1

Cl~entelnvoca Create0

T
lnstanc~a creada utrhzando constructor sln argurnentos

Contenedor lnvoca ejbRemove0

Metodo ~nvocado setSess~onMethod ejbCreate() ~nvocado con parametros

Un cllente

paslva el bean

llamadas
I I

Cllente lnvoca

Beans de sesion y Iogica de empresa


La complejidad adicional procede la necesidad del contenedor de gestionar de forma efectiva el estado por cliente: e j b A c t i v a t e ( ) , e j b p a s s i v a t e ( ) ,limites de tiempo y el requisito del cliente de controlar la creacidn y destruccion de instancias.

El cliente para la calculadora de la necesidad financiers con estado


~ s t es e el nuevo cliente. A diferencia de la versidn anterior, n o existe dependencia en el orden en que son invocados 10s mktodos. El bean de sesidn con estado ha aceptado la r e ~ ~ o n s a b i l i d a de d realizar chlculos en el orden correcto a1 final del flujo de trabajo. Alternativamente, podria procesar la informacidn a medida que vaya siendo recibida e imponer el flujo de trabajo generando una excepcidn si u n o de sus mktodos fuera invocado fuera del orden correcto:
package import impi'rt import public finCalc.statefu1; java.uti1.Properties;

ja v a x . n a m i n g . C o n t e x t ;
j avax. naming. I n i t i a l C o r , t e x t ;

class

Testclient datos

//

Comprobar

p u b l i c s t a t i c v o i d main ( S t r i n g [ I a r g s ) { try P r o p e r t i e s p r o p = nsw P L - o p e r t i e s i ) ; prop.putiCorltext.INITIAL CONTEXT FACTORY, ; "weblogic. j ndi . W L I n i t i a l C o r ~ t e x t F a c t o r y " ) p r i ' p . p u t ( C c ' n t e x t . PROVILER URL, " t 3 : / / l o c a l h o s t : 7 0 O l " ) ; Cor~text ctx Object
=

new
=

I n i t i a l C o n t e x t [ p r c ' p );

objref

ctx.lookup("StatefulFiriaricia1NeedCalculator");

F i n a n c i a l N e e d C a l c u l a t ~ i r H o m e hame = ( Fir~ar~cialNeedCalc~~latorHam j a ev )ax. r m i . P,:rtableRemoteObject e. lass); .n a r r n w ( o b j r e f , F ~ n a r ~ c i a l N e e d C a l c u l a t o r H o r n c Fir~aricialNeedCalculator calculator


=

home.create ("Daniel") ;

calculator .setParentIr~come (55000.0); c a l c u l a t o r . s e t P a r e n t I r 1 c o m e (35OOO.O) ; calculator.setGroupAssets(1O000.0, 1 5 0 0 0 0 . 0 . 6 0 0 0 . 0 ) ; c a l c u l a t o r . s e t A t t e r ~ d a r ~ c e C o s(t3 s0 0 0 0 . 0 , 5 0 0 . 0 , 2 0 0 0 . 0 ) ;

calculator.setStudentSummerWork(2500.0);

c a l c u l a t o r . remove ( ) ;

I I
1
1

catch (Exception e ) { e.printStackTrace();

Descriptores de implernentacion
~ s t es e el nuevo descriptor de i ~ n ~ l e m e n t a c i d que n , indica que es un bean de sesidn con estado:

Capitulo 15
< ! DOCTYPE

ej b-j a r PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN8' "http://java. sun. com/dtd/ejb-j > d " d t2 0 . d " d t_ 2 0 .r a jb -j e d /o m c d tu n . / s. v a j//p :th t " r a <ejb-jar> <enterprise-beans> <session> /b-name> e <ej b-name>Statef u l F i r ~ a r ~ c i a l N e e d C a l c u l a t o r <j ~home>finCalc.statefu1.Fir~ar~cialNeedCalculatorHome</home> <remote>finCalc.stateful.FinancialNeedCalculator</remote> <ejb-class>finCalc. statef~ul. ir1ar~cia1NeedCalculatorEJB</ejb-class>
<session-type>Statefu1</~essior1-type> < t r a n s a c t i o n - t y p e > C o r ~ t a i r ~ e r trar~saction-type> </

</sessior~> </enterprise-bear,s>

El a r c h i v o w e b l o g i c - e j b - j a r .xml es muy similar a1 anterior; simplemente hemos cambiado el nombre de la clase inicial y su nombre JNDI:
< ! D O C T Y P E w e b l o g i c - e j b-j a r

PLTBLIC

'-//BEA Systems, Inc. //DTD WebLogic 6.0.0 EJB//EN1 'http://www.bea.com/servers/wls600/dtd/weblogic-ejb-jar.dtdf>

< w e b l o g i c - e j b - j ar> <weblogic-enterprise-bear)> <ej b-name>Statef u l F i r ~ a r ~ c i a l N e e d C a l c u l a t o r < / e j b - n a m e > <jr~di-name>StatefulFinancialNeedCalculator</jr~di-name>


</weblogic-enter~rise-bean>

</weblogic-ej b-jar>

Ahora podemos ejecutar este ejemplo. Debemos crear un archivo JAR con nuestros archivos de clase y descriptor de implementaci6n en 10s siguientes directorios:
META-IN/ ejb-jar.xm1 weblogic-ejb-jar.xm1 firlCalc/ stateful/
F i r ~ a n c i a l N e e d C a l c u l a t o r class . Finar~cialNeedCalc~latorHorne~class

Finar~cialNeedCalculatorEJB.class
TooManyParentsExceptior~. class

A continuacion, para implementar el bean en WebLogic, ubicamos de nuevo una copia del archivo JAR en el directorio a p p l i c a t i o n s / de la instancia de nuestro servidor. Entonces ejecutamos de nuevo el cliente deprueba:
j ava -classpath

. ;weblagic.j ar finCalc. stateful .TestClient

Beans de sesion v Ioeica de empresa


y obtenemos 10s mismos resultados:
Dear Daniel, youi- n e e d has been calculated at 1050.0.

Podemos crear un segundo cliente que demuestre como 10s tres padres n o son aceptables para nuestro componente un tanto conservador y generari una excepcibn:

import import import

java.uti1. Properties; j avax.naming.Cor~text; javai:. naming. I n i t i a l C o r ~ t e x t ;

public class TestClient2 [ public s t a t i c void mair!(Strinq[] args) { try 1 P r o p e r t i e s p r o p = new F r o p e r t i e s ( ) ;

p r o p . p u t ( C o r ~ t e x t . I N I T I A L p r o p . p u t ( C o n t e x t , I N I T I A L C O N T E S T F A C T O R Y , C O N T E S T T F A C T O R Y ,
" w e b l o g i c . j n d i . W L I n i t i a l C o r ~ t . e x t F a c t o r y ") ; p r o p . p u t ( C o n t e s t . PROVIDERP,!JRL, "t3: / / l o c a l h o s t : 7001") ; Context Object ctx
=

new
=

I n i t i a l C o r i t e x t ( p r o p );

objref

c t x . lookup ( " S t a t e f u l F i r ~ a r ~ c i a l N e e d C a l c u l a t ~ ;r " )

FinancialNeedCalculatorHome
(

home = F i n a n c i a l N e e d C a l c u l a t o i L H ~ i m e )j a v a x . r m i . P o r t a b l e R e m o t e O b j e c t n a r r o w ( o b j r e f , F i n a r ~ c i a l N e e d C a l c u l a t o r H o r n e. c l a s s ) ; calculator
=

FinancialNeedCalculator

home. c r e a t e ( " D a n i e l " ) ;

c a l c u l a t o r . s e t F a ~ e r t t I r ~ c o r( n5 e5 0 0 0 . 0 ) ; calculator.cetParer~tIr~com (3 e5000.0);

calculatai.setParer~tIr~come(65000.0);
c a l c u l a t o r . setC;roiupAssets ( 1 0 0 0 0 . 0 , 150000.0, 6 0 0 0 . 0 ) ; c a l c i u l a t o r .s e t A t t e n d a n c e C o s t s ( 3 0 0 0 0 . 0 , 5 0 0 . 0 , 2 0 0 0 . 0 ) ;

calculator.setStuder1tSummerWorh(2500.0);

1 catch

(Exception e ) { e.printStackTi-ace ( ) ;

1
I

Cuando ejecutemos este cliente, debemos obtener un rastreo de pila similar a este (10s resultados variarin dependiendo del sistema operativo, del equipo virtual Java, etc.):
f i n C a l c . s t a t e f u l .Tc,oManyParentsExceptii~r~ a t weblogic. r m i . i n t e r r ~ ~ a Bl a . s i c O ~ ~ t b o n r ~ d R e q u essetn .dReceive ( B a s i c O u t b o u n d R e ~ q u e s t .j a v a : 8 5 ) ~ a s i c R e m o t e R e f . ja v a : 1 3 3 ) a t w e b l o g i c . r m i . i t ~ l t e r n a.lB a s i c R e r n o t e R e t . i r ~ v o k( ,B a t w e b l o g i c . rrni. i n t e r n a l . P r o x y S t u b . i n v o k e ( F r o z y S t u b . j a v a : 3 5 ) a t S P r o x y 2 . s e t P a r e n t 1 n c o r n e ( U r ~ k r ~ o wS ro ~u r c e ) a t f i r ~ C a l c . s t a t e f ~ .u Tl e s t C l i e n t 2 . m a i n ( T e s t C l i e n t 2 . j a v a : 2 6 )

Por supuesto, un cliente mis sofisticado hubiera capturado la excepcion y la hubiera procesado de forma elegante.

Capitulo 15

Combinar beans con estado y sin estado


Desarrollemos una versi6n final de esta aplicaci6n, en la que tenemos dos componentes: uno en la capa de control de acceso y otro en la capa de servicios. Esto hari que algunos de 10s principios de diseiio sobre 10s que hemos estado hablando sean mis explicitos. Ya tenemos nuestro componente de EJB de capa de servicios; es simplemente la versi6n sin estado que ya hemos examinado. El siguiente paso es despojar al bean de sesion con estado de todos sus cilculos y hacer que invoque en su lugar ese bean de sesi6n.

Las nuevas interfaces y cliente de la calculadora de necesidad con estado


Comenzamos con las mismas interfaces inicial y remota y la misma clase de excepci6n que en nuestro ejemplo de bean de sesi6n con estado (separado de 10s paquetes; estamos utilizando f i n c a l c . b o t h ) : El cliente tambiCn se encuentra en un paquete diferente y tiene otra ligera diferencia, ya que esti buscando un componente diferente:
Obj t c t .rbj r e f
=

c t x . l o o l . : u p ( " F i r ~ a r ~ c i a l N e e d C a l c u l a t ~ 7 r I r ~ t e ~ - t; ace")

Aparte de cambiar la busqueda, el cliente es el mismo que el del ejemplo con estado.

La nueva clase de implernentacion de la calculadora de necesidad con estado


La clase de implementaci6n es bastante diferente porque, en lugar de tener una serie de mktodos de implernentacion privados (como nuestro ultimo ejemplo), invoca sobre el bean de sesi6n sin estado para proporcionarle resultados. La especificaci6n Enterprise JavaBeans permite que componentes de una finica aplicaci6n se referencien entre ellos mediante un nombre 16gic0, normalmente (por recomendaci6n de la especificacion) en el forrnato j a v a : comp. / e n v / e j b / b e a n - n a m e . Este vinculo debe ser declarado en el descriptor de despliegue. En el period0 de implementaci6n de la aplicaci6n, el implementador vincula las referencias de 10s beans referenciados en el espacio de nombre del bean referente utilizando herramientas especificas de senidor de aplicaci6n.

El "espacio de nombre" de un EJB es simplemente la disposicidn de objetos que son accesibles a e'l a trave's de J N D I .
El desarrollador del componente EJB puede indicar el bean implementado especifico a1 que desearian que hiciera referencia la referencia, aiiadiendo un elemento < e j b- l i n k > a1 descriptor de implementaci6n. El c6digo con el que realizaremos esta busqueda:
I n i t i a l C o r ~ t e x t i r l i t i a l = new 1 1 - 1 i t i a 1 C o n t e ; i . (t ) ; fincalc. stateless. F i r ~ a r ~ c i a l N e e ~ ~ C a l c u l a t o home ~ H o = ~ ( f i n c a l c .s t a t e l e s s . F i r ~ a r ~ c i a l N e e d C a l c u l a t o r H o m e ) j a v a x . r r n i . P o r t a b l e R e r n o t e O b j e c t . r ~ a l - L - o( w i n i t i a l . lookup ( " j a v a : c o m p / e r ~ v / e j b / C a l c u l a t ~ r S e r ~ ~ i c e " ) , f inCalc. s t a t e l e s s . Fir~ar~cialNeedCalculatorHornc e .l a s s ) ;

A diferencia de un cliente aut6nom0, un EJB no necesita configurar las propiedades de context0 inicial antes de acceder a otros objetos de aplicaci6n a traves de JNDI. El contenedor manejari la configuraci6n.

Beans de sesion y logica de empresa


De no ser asi, este codigo es el mismo que hemos estado viendo en nuestros clientes durante todo el recorrido. (Estamos utilizando el nombre completo cualificado de la clase de bean de servicio, incluido el paquete ya que, de no ser asi, tendria el mismo nombre que nuestro bean de control de acceso.) ~ s t es a la clase completa:
package import import import public fincalc. hsth; j avaz. e jb. SessionBern; javaz. e j b . Seasisr~c'sritext; javaz.r~amir~g.Iriitialc'ar~teht; class
F i r i a r ~ c i a l N e e d c ' a l c ~ i l a t o ~ Ei Jm Bp i e r n e n t s

SessionBean

String double double double douhl e

a p l~ icar~t; studer~tSummerWrirh; t u i t lonAndFees; booksAndSuppl i e s ; riJ~>mFridBr_,a rd;

double 1iquidAssets; d o u b l e primaryHomeValue; d,iuble otherAssets; public public public void void void ejbActivate ( ) ejbpassivate ( ) ejbRemove() { )
{ {

1
{ )

public void ejbCreate(Strir1g a p p l i c a n t ) t h i s . applicant = applicant; parentlSet = false; = false; ~1arent2Set


1

p u b l i c v o i d setStudentSurnmerWork(~3~~1~ sb tu l~ e3 e r r t S u m m e ~ - W o ~ -{k ) t h i s . studentSummerWork = s t u d e r ~ t S u r r ~ r r ~ e r W ~ i r l : ;

public

setAttendanceCosts (double t u i tior~krdFees, d o u b l e b i ~ o k e A . r ~ d S u pire la , { d o u b l e ri~urrAr,dB,ia~-J) this.tu1tioriArldFees = t u i t i i ~ ~ r ~ F r , d F e t s ; t h i s . booksAr~dSupplies = booksFrdSupplies; t h i s . roomAridBoard = r o o m F r d B u a r ' j ;

void

public if
]

v o i d s e t PareritIrlcome ( i l ~ 3 u b l eincome) throws TooManyParentsException [ ( p a r e r ~ t 2 S e t ){ t h l - o w rirw T v v M a n y P a r e r l t s E x c e p t i o n ( ) ; else i f (parentlSet) { t h i s . parrnt2Income = income; t h i s .~arer,t2Set= true;

Capitulo 15
]

else { t h i s . p a r e n t l 1 r ~ c a r n e = incame; t h i s .parentlSet = true;

I
public setGroupAssets(doub1e liquidAssets, d o u b l e prirnaryHorneValue, double otherAssets) { this.liquidAssets = 1iquidAssets; t h i s . p r i m a r y H o r n e V a l u e = prirnaryHorneValue; this.otherAssets = otherAssets; void

public
LLY I

String

getMessage ( )

I n i t i a l C o n t e x t i r i i t i a l = new I n i t i a l C o n t e x t ( ) ; finCalc. s t a t e l e s s . Fir~ar~cialNeedCalculatorHorne home = ( f i r ~ C a l cs .t a t e l e s s . Fir~ar~cialNeedCalculatorHom 1 e j a v a x . rrni .PortableRernateObject. n a r r o w ( i r 1 i t i a l .l o o k l ~ p ("java:ci~rnp/er~v/ejb/CalculatorService"), f i n C a l c . s t a t e l e s s . F i r ~ a n c i a l N e e d C a I c ~ ~ l a t o r H o rc n lea . s s ); fir1~alc.stateless.Fir~ar~cialNeedCa1cula c tao l~ culator
=

horne.create(1;

d~2ubleattendanceCost = c a l c u l a t o r . c a l c u l a t e A t t e r ~ d a r ~ c e C o( s tt u i t i o r ~ A r ~ d F e e s , booksAndSupplies, r o o r n A r ~ d B o a r d; ) double parent1 = c a l c u l a t o r . calculate~arer~tCor~tribution(Farer~tlIr~came) ; duuble parent2 = c a l c u l a t o r . c a l c u l a t e P a r e r ~ t C o r ~ t r i b u t i i ;( r p~ arent21r1come) ; d o u b l e grouF


=

calculat~r.calculatetiro~pCor~tr1b1~t~or~(1~qu~dAssets,
prlrnaryHomeValue, otherAssets); dauble parentsCont~-ibution= calculator. calculateParer~tsCor~tributio (r p~ a r e r ~ t l ,parent2, group 1 ; double need
=

calculator.calculateNeed~atter~dar~ceCast,
parentsCont r i b u t i o n , studentSummerWork1;

1
)

return catch throw catch throw catch throw

calculator.getMessage(applicant, (javax.ejb.CreateEzceptior~ c e ) {
new j a v a x . e j b . E J B E x c e p t i c n i c e ) ; ( ja v a x . n a r n i n g . N a m i r ~ g E x c e p t i o r 1 n e ) new j a v a x . e j b . E J B E x c e p t i o r ~ ( r ~ e;) ( j a v a . rmi . R e r n o t e E x c e p t i o r ~ r e ) { new j a v a x . e j b . E J B E x c e p t i o i - I ( r e ) ;

need);

I I
public void s e t S e s s i o n C o n t e s t ( S e s s i o n C o r ~ t e x tc t x ) throws javax.ejb.EJBException, java.rrni.RernoteException

{I

Beans de sesion y logica de empresa


Los descriptores de implernentacion
El descriptor de implementaci6n proporciona informaci6n a1 contenedor sobre ambos beans. TambiCn configura la referencia desde nuestro bean de sesi6n con estado a1 bean sin estado:
< ! DOCTYPE

ejb-jar PUBLIC " - / / S u n M i c r o s y s t e m s , "http://java. sun. c o m / d t e j b a r " h t p : / j a v . s u n c o m / d t e j b a r _ 2 0 . d t 2 O . d t " >

I R ~ //DTD .

Enterprise

JavaBeans

2. O//ENW

<ejb-jar> <enterprise-beans> <session> <ejb-r~ame>Fir~ancialNeedCalculatorIr~terface< b/- e nj ame> < h o m e > f i n C a l c .b o t h . F i r ~ a r ~ c i a l N e e d C a l c u l a t o r H o m e < / h o m e > <remote>finCalc.both. Fir~ar~cialNeedCalculator</remote> <ejb-class>finCalc. both. Fir~ar~cialNeedCalculatorEJB</ejb-class> <session-type>Statefu1</sessior1-type>

<transaction-type>Cor~tair~er</trarIsactior~-type>
<ejb-ref> < e jb - r e f - n a m e > e j b / C a l c u l a t o r S e r v i c e < / e j b-ref-name> < e j b - r e f - t y p e > S e s s i o r ~ < / e jb - r e f - t y p e > <home>finCalc.s t a t e l e s s . Fir~ar~cialNeedCalculatorHome</home>

<remote>fir~Calc.stateless.Fir1ar~cia1NeedCalculator</remote> <ejb-link>FinancialNeedCalculatorService</ejb-lir~k>
< / e jb - r e f > </session> <session> < e jb - r ~ a m e > F i r ~ a n c i a l N e e d C a l c u l a t o r S e r v i c e < / e j b - r ~ a m e >

<home>finCalc.stateless.Fir~ar~cialNeedCalculatorHome</home>
<remote>finCalc.s t a t e l e s s . Fir~ar~cia1NeedCalculator</remote>

<ejb-class>fir~Calc.stateless.Fir~ar~cia1NeedCalculatorEJB</ejb-class>
<session-type>Stateless</sessior1-type> <trar~saction-type>Cor~tair~er</trar~sactior~-type> </session> </enterprise-beans>

w e b l o g i c - e j b- j a r x m l

contiene ahora definiciones de ambos inicios:


Inc.//DTD WebLogic 6.0.0 EJB//EN'

< ! DOCTYPE w e b l o g i c - e j b - j a r PUBLIC ' - / / B E A S y s t e m s ,

'http://www.bea.com/servers/wls600/dtd/weblogic-ejb-jar.dtd'>
<weblogic-ej b-j a r >

Capitulo 15

Debe crear un archivo JAR con sus archivos de clase y descriptor de implementacion en 10s siguientes directorios:
I4ETA-INF/ ejb-jar.xrnl w e b l o g i c - e j b - j ar.xrnl finsalc/ both/
F i n a n c i a l N e e d C a l z ~ l l a t t ~c r. lass Finan~ialN~edCalcuiatorHc~m >e l. ass F i n a r ~ c i a l N e e ~ ~ C a l c u l a t u r Ec J lBa . s s Tool.lar~yParerctsE:iceptior~ c .l a s s stateless/ F i n a n ~ i a l N e e d C a l c u l a t o rc .lass F i n a r ~ c i a l N e e d S a l c b l a t i i r H o m ec .1 a s s F i r ~ a n c i a l N e e d C a l c u l a t t i r E J P .c l a s s

Implemente este archivo JAR en el sewidor de su aplicacion y ejecute el cliente, para obtener el mismo resultado anterior.

Implementation de nuestra aplicacion


Es hora de comenzar la implementation de la aplicacion de muestra para la que ya hemos realizado algfin anilisis anteriormente. Ahora, icomo traducimos este analisis en una verdadera implementacion? Cualquier implementation de software estari influida por una serie de factores, incluido costes de desarrollo, requisitos de rendimiento y reajustabilidad, expectativas del usuario, personal, etc. En este caso, asumiremos que estos factores nos motivan para conseguir una implementacion sencilla, fundamentalmente porque asi es mejor para el objetivo acadtmico de explicar el uso de 10s EJB. La portion del modelo de anilisis que hemos elegido para su implementaci6n tiene cuatro objetos entidad: producto, instrucciones de encaminamiento, pedidos y envios.
L I

Un producto consistiri en un identificador, un nombre legible por el usuario y una lista ordenada de entidades de instruccion de redireccionamiento para controlar el proceso de fabrication

O U n pedido consistiri en el producto solicitado, una clave de identification (nfimero de pedido mis divisi6n de ventas) y un estado (abierto, cancelado, en proceso de fabricacion y completado)
La informaci6n de envio consistiri en una clave de pedido, un almackn de carga, un campo de fabricaci6n y una fecha completada

O Una instruccion de redireccionamiento tiene una secuencia (un nfimero entero) y una instrucci6n
(String)

Beans de sesion y logica de empresa


Los objetos entidad del modelo de anilisis se traducirin habitualmente en beans de entidad o atributos de beans de entidad, en la irnplementacibn. En este caso, tendremos dos beans de entidad:

o Unpedido
0

U n producto, con instrucciones de redireccionamiento como un atributo sencillo

Observe que, en otras circunstancias, las instrucciones de redireccionamiento quiza's necesiten una entidad de primera clase. Una vez trabaji en un sistema de Planificaci6n de Recursos de Empresa donde k t e habria sido el caso ya que las instrucciones de redireccionamiento eran compartidas por mriltiples productos. Aqui su ciclo de vida depende completamente de su producto progenitor, que siempre hace de una entidad un firme candidato a ser implementada como atributo.
Podria tener sentido actualizar la informaci6n de envio directamente desde un bean de sesi6n. Observe que este bean de sesi6n puede manipular directamente la base de datos, per0 no representa una "entidad de envio". La raz6n de este enfoque es la sencillez de desarrollo. Igualmente, actualizando directamente la base de datos, estamos demostrando una opcion alternativa vilida de la que deberiamos ser conscientes. El c6digo es bastante sencillo por lo que s61o tenemos dos beans de sesi6n responsables de la implementaci6n de todos 10s objetos control e interfaz:
0

U n bean de sesi6n sin estado utilizado para gestionar pedidos, que t a m b i h tiene una funci6n de utilidad para crear productos de muestra U n bean de sesi6n con estado utilizado para controlar el proceso de fabrication

Incluso con la sencillez de 10s requisitos, estamos engafiando un poco; no tiene sentido mezclar la creaci6n del producto con la gesti6n de pedidos. Una vez que hemos comenzado a modelar la complejidad de una organizaci6n real, querremos ernpezar a dividir nuestra funcionalidad en componentes mis cohesivos de control de acceso y de nivel de servicios. Consideremos ahora las funciones que desempefian estos dos beans de sesibn. En primer lugar, cada uno de ellos sirve como objeto interfaz para algunos de 10s clientes de esta aplicaci6n. El EJB que controla el proceso de fabricaci6n gestiona el estado conversacional para sus clientes de fabricaci6n. Pede utilizar este estado directamente para garantizar el cumplimiento de las reglas del flujo de trabajo (corno que un producto debe ser seleccionado antes de que se muestre su redireccionamiento). Sin embargo, debemos tener en cuenta que aqui intervienen dos roles distintos: la implementaci6n de objetos interfaz y la implementaci6n de objetos control. Un estado de la aplicacibn debe estar contenido en el cliente o en un objeto "interfaz". En realidad, utilizar este estado es realmente la funci6n de un objeto de servicio, si tuvieramos que emparejar 10s componentes EJB con sus funciones de anilisis perfectamente. El EJB de sesi6n sin estado que gestiona pedidos act6a como un objeto interfaz para muchos clientes, per0 tambikn como mero objeto de control para el EJB de fabricaci6n. Como 10s mitodos de empresa en 10s EJB tienden a tener funcionalidad gruesa, no es extrafio que un cliente con un "tema" similar a un determinado bean de sesion de capa de servicio pueda utilizar ese bean directamente como su interfaz. Sin embargo, si la capacidad de reutilizaci6n y de mantenimiento son puntos importantes, debemos evitar la especializaci6n de este bean de sesion para clientes concretos. En su lugar, introduzca un componente que implemente independientemente la funcionalidad de la interfaz si es necesario. Observe que crear listas de entidades es una funci6n de objetos de control en el modelo de anilisis per0 la situaci6n es mis cornplicada en una implementaci6n que utiliza tecnologia Enterprise JavaBeans. Se pueden producir colecciones de entidades utilizando un mitodo de factoria sobre una interfaz inicial de bean de entidad; estos mitodos de factoria se conocen como mktodos buscador. Bisicamente, devuelven una interfaz remota EJB o una colecci6n de interfaces remotas que cumplen 10s criterios definidos por la aplicaci6n. Sin embargo, devolver una colecci6n de entidades a1 cliente viola la directriz que establece que la implementaci6n del modelo de andlisis debe quedar oculta detris de una fachada tambiin puede tener

Capitulo 15
consecuencias negativas para el rendimiento. Por lo tanto, se recomienda utilizar de nuevo la fachada de bean de sesi6n: este EJB invocard un buscador sobre un bean de entidad y realizard algunas transformaciones adicionales (como restringir 10s valores de retorno o volver a empaquetarlos en objetos Java) antes de devolverlos a 10s clientes. Esto se consigue normalmente con interfaces locales. Los clientes son abstracciones completas. En el mundo real, serian probablemente aplicaciones Web o clientes GUI Swingy la funcionalidad estaria mis nitidamente definida y seria mis flexible. Aqui existen unicamente para probar c6digo de lado servidor y demostrar c6mo pueden utilizarse 10s EJB. Hay cuatro clientes, aunque uno de esos clientes se extiende por dos clases ejecutables. Observe que todos 10s accesos de cliente son a uno de 10s beans de sesi6n. Manteniendo el patr6n de fachada, ningun cliente que no sea bean accede a un bean de entidad:
0

La clase create products invoca una funci6n de utilidad para crear productos de muestra para ser utilizados en otros ejemplos. La clase PlaceSampleOrders situa seis pedidos que deben ser entregados en diferentes fechas. Dos de 10s pedidos han sido solicitados con tanta antelaci6n que todavia no deben ser fabricados; dos pedidos ya estin preparados para ser fabricados y pueden ser completados a tiempo; y dos van atrasados si tenemos en cuenta el tiempo de producci6n.
Managesampleorders imprime 10s pedidos atrasados en System. out. Entonces cancela el

primer pedido atrasado.


0

El cliente final tiene dos clases, BeginManuf acture y CompleteManuf acture; kstas son dos clases ejecutables diferentes. La clase BeginManuf acture crea un bean de sesi6n con estado que utiliza para imprimir 10s pedidos susceptibles de fabricaci6n. Entonces selecciona el primer pedido disponible, codifica un controlador para ese EJB para ser utilizado por la siguiente aplicaci6n y sale. La clase CompleteManuf acture imprime en orden 10s redireccionamientos del producto, envia el producto e invoca remove ( ) sobre el bean de sesion.

Esta aplicaci6n de prueba es mucho mds sencilla de lo que alguna vez sera una aplicaci6n real. Sin embargo, las tkcnicas aqui demostradas podrian ser valiosas para sus esfuerzos de desarrollo utilizando tecnologia Enterprise JavaBeans. El cddigo completo para estos ejemplos puede ser descargado desde el sitio Web de Wrox en http://www.wrox.com/.

Clientes e interfaces de Iogica de empresa


En esta secci6n, examinaremos la implementaci6n de interfaces iniciales y remotas de 10s beans de sesi6n, y 10s clientes que las utilizan. En el proceso de desarrollo, las interfaces proporcionan un contrato a 10s clientes, que no necesitan conocer 10s detalles de la implementaci6n. ~ s t es e un pequefio resumen de las clases que veremos en esta secci6n. Primero, en el paquete
factory.manage-orders:
0 Manageorders (interfaz remota)

NoSuchProductException

Ove rdueOrderView

Beans de sesion y logica de empresa


Enelpaquetef a c t o r y .manuf a c t u r e :
O M a n u f a c t u r e (interfaz remota) O Manuf a c t u r eHome (interfazinicial)

Finalmente,enelpaquetef a c t o r y . c l i e n t :

Createproducts

Mezclado con este cbdigo, hay dos nuevos debates de tkcnica EJB. El primer0 es el procesamiento de controladores y el segundo es cbmo manejar el comportamiento de listado. Las interfaces remotas de 10s dos beans de sesibn, f a c t o r y . m a n a g e - o r d e r s . M a n a g e o r d e r s y f a c t o r y .manuf a c t u r e . M a n u f a c t u r e , representan toda la lbgica de empresa disponible para 10s cuatro clientes.

El EJB ManageOrders
M a n a g e O r d e r s es el bean de sesibn sin estado. Su interfaz remota es la siguiente:
pacl-age f a c t o r y . manage o r d e r s ;

i m p o r t ja v a x . e j b . + ; lmport 1 a v a . u t i l . Date; i m p c , r t j a v a . r m i .R e m o t e E x c e p t i o r t ; import. f a c t o r y . o r d e r . O r d e r N o t C a r ~ c e l a b l e E x c e p t i o r ~ ; p u b l i c i n t e r f a c e Mar~ageOrders e x t e n d s EJBObject { void p l a c e O r d e r ( i n t s a l e s D i v i s i o r ~ , irjt orderNumber, S t r i n g p r o d u c t , Date dateDue) t h r o w s Rerrm?teExceptior~, NoSuchPr~ductException,

DuplicateOrderException;
void c a r ~ c e l O r d e( ri n t salesilivision, throws RemoteExceptior~, NoSuchOrderException, i r ~ to r d e r N u m b e r )

OrderNot~ahcelableEsception;
OverdueOrderView[] getOvtrdueOrders ( ) throws throws RemoteException; RemoteExctption;

Oper,OrderView[] g e t S c h e d u l a b l t O r d e r s ( 1 void void void createSampleFroducts

(I

throws

RemoteException; name) irit throws RernoteException; String instr~uctior~)

c r e a t e F r o d ~ ~ (cS ttring i d ,

String

addRoutingInstructior~(Strir~g id,
throws RemoteException;

sequence,

Beans de sesion y Iogica de empresa


O t r o tema estrechamente relacionado que no queda demostrado por esta aplicaci6n de myestra es c6mo transferir datos sobre una h i c a entidad desde el servidor a una aplicaci6n cliente. Este es un requisito comb. Muchas aplicaciones presentarin pantallas disehadas para editar 10s datos asociados a una entidad como un comprador, un product0 o una compafiia. Los mismos problemas que motivan el uso del patron de fachada evitan que llamadas individuales al servidor recuperen o establezcan datos. Esto s i p i f i c a que n o deberiamos utilizar una secuencia de llamadas como g e t F i r s t N a m e ( ) ,getMiddleName ( ) ,getLastName 0 , g e t A d d r l ( ) , g e t A d d r 2 (),etc.Los datos necesitan ser transferidos en una colecci6n de algGn tip0 (nuestro metodo podria ser g e t S i m p l e C u s t o m e r D a t a 0). i C 6 m o deberia ser esta coleccibn? Las dos estrategias bisicas reflejan aquellas destinadas a devolver sencillas listas de informaci6n. La primera esti destinada a devolver un objeto vista, que debe ser una simple colecci6n serializable de datos, c o m o O v e r d u e O r d e r V i e w o OpenOrderView. Este es el c6digo para O p e n O r d e r V i e w ; observe que son s d o datos estructurados sin ninguna funcionalidad:
package import import
f actnry.manaqe

orders;

java.io.Serializable;

ja v a . u t i l . Date;
a s s OpenOrderView irnplerner~ts S e r i a l i z a b l e f i r i a l i r ~ ts a l e s D i v i s i o n ; f i n a l i n t orderNurnber; f i n a l S t r i n g ~mroduct; f i n a l Date d a t e h e ;
{

public cl public public public public public

O p e r ~ O r d e r V i e w ( i n ts a l e s D i v i s i o r ~ , i r l t ordel-Number, S t r i n g p r o d u c t , Date dateDue) { this.salesDivision = salesDivi~ic~r~; t h i s .orderNumber = orderNurnber; t h i s . product = product; this.dateDue = dateDue;

Y este es el codigo p a r a O v e r d u e O r d e r V i e w :
packaqe f a c t ~ > r y . r n a r l a q eo r d e r s ;

imp,>rt j a v a . i o . S e r i a l i z a b l e ; i m p o r t j aX:a . u t i l . D a t e ; p u b l i c c l a s s OverdueOrderView irnplemer~ts S e r i a l i z a b l e public final i n t salesDivision; p u b l i c f i r l a 1 i r ~ tc , r d e r N u m b e r ; ~ , u b l i cf i r j a l S t r i n g p r o d u c t ; p u b l i c f i n a l S t r i r ~ gs t a t u s ; p u b l i c f i n a l Date dateDue; public O v e r d u e O r d e r V i e w ( i r i t s a l e s f i i v i s i ~ i r ~ i,r l t S t r i n g prrjduct, Stririq Date dateDue) [ this.salesDivisior1 = salesDivision; t h i s .orderNurnber = orderNumber; t h i s .product = product; this. status = status; this.dateDue = dateDue;
{

orderNurnber, status,

Capitulo 15
La ventaja de este enfoque se encuentra en que el c6digo es sencillo de prograrnar y entender; la desventaja es que el objeto vista es especifico de un cliente deterrninado o de un tip0 de cliente deterrninado, que presenta acoplarniento entre cliente y servidor. La segunda estrategia consiste en utilizar una clase genkrica con datos autodescriptivos. A1 referirnos a comportarniento de listado, hemos rnencionado la irnplernentaci6n de j a v a s q l .R e s u l t S e t . Corno estarnos enviando informaci6n sobre una unica entidad y corno esa inforrnaci6n podria tener datos no tabulares (datos en irbol o datos en cuadricula subordinada), R e s u l t s e t no es la interfaz ideal en este caso puesto que este tip0 asocia rnuy especificarnente filas a una base de datos y no a una estructura rnis compleja. Una buena alternativa es devolver una j a v a .u t i l .Map, con pares valor-clave que representen una descripci6n de 10s datos (quizas un nurnero entero identificador) y 10s datos. El cliente podria solicitar unicarnente 10s datos que necesitara y el servidor podria enviar estos datos sin conocirnientos previos de la solicitud.

El EJB de fabricacion
M a n u f a c t u r e es el bean de sesi6n con estado; su interfaz remota es asi:
package import impcrt import import f a c t o r y .manufacture; javax.ejb.*; j a v a . r m i .R e m o t e E x c e p t i c r , ; f a c t o r y . manage o r d e r s . Oper~OrderView; f a c t o r y . m a n a g e nrders.NoSuchOrderException;

p u b l i c i n t e r f a c e M a n u f a c t u r e e x t e n d s EJBObject { O p e n o r d e r v i e w [ I g e t O p e n O r d e r s ( ) t h r o w s Kern,3teException; void

selectForManufacture(int s a l e s D i v i s i o n ,
throws

i r ~ to r d e r n u m b e r ] RemoteException, NoSuchOrderE,xception, BadStatusEsception; throws throws irlt RemoteExceptiort, RemoteException, loading dock) NoSelecti~3r~Exception; NoSelectionException; RemoteException, NoSelectinnExceptior~;

boolearl String void

hasNextRoi~ting ( ) getNextRouting
( )

ship(Strir1g c a r r i e r ,

throws

Observe que, a diferencia del b e a n ~ a n a g e o r d e r s existe , un orden presupuesto en estas llarnadas de rnktodo. Debe primer0 seleccionar un pedido para fabricaci6n. Despuks recorra 10s redireccionarnientos (presurniblernente construyendo el producto a rnedida que vaya avanzando). Finalrnente, envie el producto. Si olvida seleccionar el pedido antes de intentar leer sus encarninarnientos, o antes de enviarlo, se lanzari una excepcicin N o S e l e c t i o n E x c e p t i o n . Resulta ficil de programar con un bean de sesi6n con estado. Si hubikramos hecho de kste un bean de sesi6n sin estado, hubikrarnos necesitado pasar el pedido seleccionado como parimetro para cada llarnada de rnktodo. Tarnbih hubikramos necesitado pasar un cursor de algun tipo para 10s rnktodos h a s N e x t R o u t i n g ( ) y g e t N e x t R o u t i n g 0 , porqueel bean, a1 no tener estado, n o podria registrarlo por nosotros. Tarnbikn a diferencia del b e a n ~ a n a g e ~ r d e rhay s , algo interesante en la interfaz inicial: un rnktodo c r e a t e ( ) con un parirnetro. Este parirnetro identifica la "cklula" que esti fabricando el producto. Cuando el producto es enviado, esta inforrnaci6n seri afiadida autorniticarnente a la tabla de envios. ~ s t a es dicha interfaz inicial:
package factory.mar~ufacture;

Beans de sesion y logica de empresa

import import

j a v a x . e j b . +; j a v a . rrni . R e r n o t e E x c e p t i o n ;

p u b l i c i n t e r f a c e M a n u f a c t u r e H o m e e x t e n d s EJBHome { Manufacture create(Strir1g manufactureCellID) t h r o w s RernoteException, C r e a t e E x c e p t i o n ;

Como recordatorio, u n bean de sesio'n sin estado no puede tener ningun para'metro en su metodo c r e a t e 0 , n i tampoco hay ninguna razo'n por la que desear que lo tenga. Puesto que u n bean de sesi6n sin estado no guards infonnacio'n en nombre de un cliente, cualquier infonnacidn que haya proporcionado en u n mitodo c r e a t e () habra' desaparecido para cuando realice la primera llamada de metodo de empresa. Punto fundamental: si ha visto una interfaz para u n bean de sesidn sin estado, ya las ha visto todas.

Los clientes de aplicacion


Los clientes referencian a1 servidor por completo a travCs de dos interfaces de bean de sesi6n. En tCrminos sencillos, todos 10s clientes son clases con s610 una funci6n estdtica m a i n ( ) . Todas siguen un sencillo patr6n de dos pasos: Obtienen una referencia a un bean de sesi6n

O Utilizan esa referencia para alcanzar algGn prop6sito de empresa


En estos ejemplos se obtiene una referencia a un bean de sesi6n en uno de 10s dos modos. Primero, estd el camino "obtener la interfaz inicial desde JNDI/crear un bean de sesi6nU.Ese c6digo, para el bean de sesi6n sin estado, es como sigue:
C o n t e x t P r o p e r t i e s F a c t o r y f a c t o r y = new C o r ~ t e x t P r o p e r t i e s F a c t o r (y ) ; Properties prop = factory.getIr~itialCrir~textPropertie ( )s ; I n i t i a l C o n t e x t i n i t i a l = new I n i t i a l C o n t e x t ( p r o p ) ;

Object

homeObj e c t

i n i t i a l . lookup ("ManageOrders") ;
=

ManageOrdersHome

home

(ManageOrdersHome)

PortableRemote0b]ect.r~arrow~homeObject, Manage0rdersHome.class);
Manageorders marlageorders
=

home. c r e a t e (

) ;

0 este codigo, para el bean de sesi6n con estado (la unica verdadera diferencia es el parimetro para el
metodocreate
()

):

C o n t e z t P r o p e r t i e s F a c t o r y f a c t o r y = new ContextPropertiesFactory ( ) ; P r o p e r t i e s p r o p = f a c t o r y . g e t I r ~ i t i a l C o r ~ t e x t P r o p e r t i (e) s; I n i t i a l C o n t e z t i n i t i a l = new I n i t i a l C o n t e x t ( p r o p ) ; Object homeobject


=

i n i t i a l . lookup("Manufacture");

M a n u f a c t u r e H o m e home = ( M a n u f a c t u r e H o m e ) PortableRemoteObject. narrow(homeObject, Manufacture manufacture


=

ManufactureHome. c l a s s ) ;

horne.create(MANUFACTURE-CELL);

C o n t e x t P r o p e r t i e s F a c t o r y es una clase que escribiremos nosotros mismos. Hay muchas formas de configurar las propiedades para el context0 inicial; las dos mejores consisten probablemente en situar un archivo j n d i .p r o p e r t i e s en la ruta de clase o cargar un archivo de recursos de propiedades especificas

Capitulo 15
de la aplicaci6n utilizando el mitodo g e t R e s o u r c e A s S t r e a m ( ) . Para que quede rnis claro lo que esti sucediendo, hernos elirninado este nivel de indirecci6n de 10s clientes de rnuestra. Este es el ~ontext~ro~erties~actor~~araWebLogic:
package import import public factory. cllents;
j avax.narnin~.Context; j ava . u t i l . Properties;

class

Ccr~textPropertiesFa,_tary (

public Properties Properties prop

g e t I n i t i a l C o r ~ t e x t P r o p e r t i e s )I { new P r o p e r t i e s ( ) ; prop.setProperty(Cor~text.INITIALCONTEXT FACTORY, ") " w e b l o g i c . j r ~ d .i W L I r ~ i t i a l c " o r ~ t e x t F a c t o r y ; p r o p . s e t p r o p e r t y ( C ~ ~ r ~ t PROVIDER e r t . LIRL, " t 3 : / / l o c a l h o s t : 7 0 0 1 " ) ; r e t u r n prop;
=

1
publit: v o i d m a k e P r o p e r t i e s D e f a 1 ~ 1( t) [ S y s t e m . s e t P r o p e r t i e s (getIr~itia1Co1- text properties

1;

En general, podernos pasar estas propiedades al context0 inicial en su constructor. Si el vendedor de nuestro contenedor de EJB requiere que estas propiedades Sean establecidas cuando restaurernos una referencia EJB desde un controlador, necesitarernos establecer las propiedades de sisterna con estos valores, corno hacemos e n m a k e P r o p e r t i e s D e f a u l t 0. El segundo rnodo de adquirir una referencia a un bean de sesi6n en estos ejernplos es obtenerla desde un controlador que haya sido codificado en el disco. Al final del cliente "iniciar fabricaci6nU, el controlador se codifica del siguiente rnodo:
H a n d l e h a r d l e = r n a n l ~ l f a z t u r eg . etHandl t ( ) ; FiltOutputStream file-out = n e w F i l e O u t p u t S t r e a m ( F 1 L E NAME); O b j e z t O u t p u t S t r e a m n u t = new O b j e c t O u t p u t S t r e a r n (f i l e - Z u t ) ; j u t . w r i t e o b j e c t ( t ~ a r l d l e; ) S-/cttrn.out . p r i n t l r ~ ("Written i ~ h j e z t for next stage.") ;

A1 principio del cliente "cornpletar fabricaci6nW, la referencia a1 bean de sesi6n sin estado es restaurada del siguiente rnodo:
F i l e I n p u t S t r e a r n i n S t r e a m = r ~ e w F i l e I r ~ p u t S t r e a m ( F 1 L ENAME); ta tr n ! i r ~ ~ t r e a m ;j O b j e c t I n p u t S t r e a r n i n = r ~ e w 0 b j e c t ~ n p u t r~ H a n d l e h a n d l e = ( H a n d l e )i n . r e a d O b j e c t ( 1 ; Manufacture manufacture = (Manufacture) E 1 a r t a b l e R e r n o t e O b j e c t . r l a r r o w ( h a r , l l e .g e t E J B O b j e c t ( ! , t ' l a n u f a c t u r e . c l a s s

) ;

Tanto las referencias iniciales corno las rernotas tienen controladores que se pueden codificar y transferir entre programas utilizando mktodos corno archivos, sockets o RMI. Pueden ser guardados en la sesi6n de un servlet e incluso pueden ser enviados por e-mail (0, de forrna rnis prictica, trasladados con software interrnediario de rnensaje). Recuerde, no obstante, que las referencias a objetos rernotos en EJB son de un linico hilo. El acceso sirnultineo desde rnliltiples clientes o rnliltiples hilos es un error y tiene corno resultado la generaci6n de una excepci6n. Por ejernplo, no se perrnite a un cliente buscar un bean de sesi6n con estado y despuis producir hilos para invocar sus rnetodos de ernpresa de forrna concurrente. Exarninernos ahora estos dos clientes en su totalidad. Ernpezarernos por BeginManuf a c t u r e .

Beans de sesion y logica de empresa


El cliente Beginklanufacture

Este cliente lee 10s pedidos pendientes e inicia la fabricaci6n de 10s bienes irnplicados. Se detiene a rnedio carnino, a h a c e n a el controlador de ManufactureEJB en un archivo codificado y sale. Este archivo seri leido entonces por el siguiente cliente para cornpletar el pedido (en una aplicaci61-1 real, necesitariarnos un rnodo rnis enkrgico que un archivo de pasar esta inforrnaci6n, corno una base de datos):
pac1:aqe factury. clients;

i r n ~ ~ n rjt a u a . r r n i . R e r n o t e E x c e p t i o r ~ ; imF,.r)rt j c l v a s . e j b . + ; i m p o r t ja-.,as. riarnir~g. +; ejc t ; i m p . . r t ] a - / a x . mi. F < ? L - t a b l e R e r n o t e O b im~~cir? ja-/a.util. F~-~>pe~-ties; imp:,rt l a v a . ic'. +;

pri.;stc s t a t i c ~ ~ r i v a ts et a t i c

firla1 final

S t r i r t q l4ANlJFACTTJRE CELL = " S t a t i o n l " ; S t r i n g F I L E NAME = " C : / c u r r e n t p r o d u c t . s e r W ;

try

C n n t e x t P r ~ ~ p e r t i e s F a c t o rf ya c t o r y = r~ew2~3r~testPrapertiesFactor ( y ) ; P r c p e r t i e s F>raF> = f a c t o r y . g e t I r ~ i t i a l C o r ~ t e x t P r o p e r t i e ( )s ; I n i t i a l C a n t e s t i r l i t i a l = new I n i t i a l C o n t e x t ( p r o p ) ; Object homeobject


=

i n i t i a l . lookup ("Manufacture") ;

M a n u f a c t u r e H o m e home = ( M a n u f a c t u r e H o r n e ) P c , r t a b l e R e m o t e O b j e c t . n a r r o w ( homeObj e c t , ManufactureHome. c l a s s ) ; M a r l u f a c t u r e m a n u f a c t u r e = home.create(MANUFACTURE C E L L ) ; OpenOrderView[ 1 o p e n o r d e r s manufacture. getopenorders ( ) ;


-

~f

( o p e n O r d e r s . l e n g t h == 0 ) { System.out . p r l n t l n ("Nothing t o return;

rrlake;

yc.

h~rne.");

I
System.out.println("Se1ectir~g f r o m t t ~ e f o l l o w i n y a p e n 3 1 - d e r s : " ) ; itel-tt) { f o r ( i n t i t e r = 0; i t e r < o p e n 0 r d e r s . l e r t q t h ; OpenOrderView o p e n o r d e r = o p e r ~ O r d e r s ( i t e r 1 ;
System.out . p r i n t l n ("Sales Di-/ision: " t openOrder.salesDi-/isior1+ "; O r d e r # : " t o p e n o r d e r . o r d e r N u r r ~ b e r t "; P r a d u c t : " t o p e n O r d e r . p r u d u c t + " D a t e Aue: " t openOrder.dateDue);

//

for

Obtener e l primer pedido a b i e r t o ( i r l t i t e r F i n d = 0; i t e r F i r l d < a p e r t O r d e r s . l e n q t h ; iterFind++) { try I

Capitulo 15
OpenOrderView o p e n o r d e r = o p e r l o r d e r s [ i t e r F i n d ] ; manufacture. selectForMar~ufacture ( o p e r l o r d e r .s a l e s D i v i s i o r ~ , o p e n o r d e r . orderNumber j ; Handle handle = manufacture. getHandle ( ) ; F i l e o u t p u t s t r e a m f i l e o u t = new F i l e O u t p u t S t r e a m ( F 1 L E NAME); Obj e c t O u t p u t S t r e a m o u t = new O b j e c t O u t p u t S t r e a m ( f i l e o u t ; o u t . w r i t e O b j e c t ( h a n d l e ); System.out . p r i n t l n ("Written o b j e c t f o r next s t a g e . " ) ; break; c a t c h (factory.mar~ufacture.BadStatusException b s e ) {

/ / A l g u i e n s e ha a p r o p i a d o d e bse .printStackTrace ( ) ;

61

antes

que

nosotros

I
\

catch (FileNotFour~dException f n f e ) { f nf e . p r i n t S t a c k T r a c e ( ) ; c a t c h (RemoteException r e ) { re.printStackTrace0; catch (IOException i o e ) { ioe.printStackTrace ( ); c a t c h ( f a c t o r y . manage o r d e r s . N o S u c h O r d e r E x c e p t i o n nsoe .printStackTrace ( j ; c a t c h (NamingException n e ) { ne. printStackTrace ( ) ; catch (CreateException c e ) [ ce.printStackTrace ( ) ;

nsoe )

El cliente "comenzar fabricaci6nW irnprirne una lista de 10s pedidos abiertos susceptibles de fabrication. El cliente no necesita preocuparse sobre estos requisitos de susceptibilidad; este es una regla de empresa que es implernentada sobre el servidor. A continuaci6n el cliente selecciona uno de estos elementos para su fabricaci6n. Este c6digo es ligerarnente mis complicado que cualquiera de 10s otros c6digos de lado cliente que encontrarernos. Tenemos una lista de pedidos abiertos; ipor quk necesitamos capturar una excepcidn que s61o se generaria si intentiramos fabricar un pedido que no estuviera abierto? Entre el momento en que obtuvimos la lista de pedidos abiertos y el momento que intentarnos seleccionar uno de esos pedidos para su fabricacibn, algunas otras cklulas de fabricaci6n ya podrian haber empezado a trabajar en ese mismo pedido. El problema esti en que podriamos estar trabajando con datos desfasados. En una 6nica transacci6n (y dependiendo de niveles aislados), podriamos estar seguros de que nuestra lista de pedidos abiertos seguiria abierta hasta que seleccioniramos uno de ellos para su fabricaci6n. Pero almacenariamos en cache 10s datos en el cliente (en forma de matriz openorders) y ahora debemos considerar la posibilidad que nuestros datos esten desfasados y, por lo tanto, el ciclo. Observe que nuestro ciclo, aunque tiene la virtud de la simplicidad, no es una solucion perfecta para este problema. Podriamos recorrer la lista original completa de pedidos abiertos sin encontrar uno que todavia estuviera abierto, en cuyo caso saldriamos del prograrna sin rnis trabajo. Pero, mientras tanto, podrian haberse realizado ciertos pedidos. Con la soluci6n actual, necesitamos ejecutar el programa de nuevo si esto ocurre. Este es un caso especial de un problema mis general.
El cliente CompleteManufactured

Este cliente continfia donde abandon6 el cliente anterior. Lee el archivo codificado que contiene el
Manuf acturedEJB parcia1 y cornpletala fabricaci6n:

Beans de sesion y logics de empresa


package import import import import import Import import lmport lmport public factory.clients;
java.rmi.RemoteException; j a v a x . ejb. + ; javax. naming. + ; javax.rmi.Fortab1eRemoteObject; java.uti1. Properties; j a v a . io. + ;

factory.manufacture.Manufacture; factory.manufacture.Mar~ufactureHome; factory .manage o r d e r s .OpenOrderView;

class CompleteManufacture

El archivo para la siguiente variable FI LE-NAME podria necesitar una modificaci6n para coincidir con nuestro sistema. Ademis, en una situaci6n real, las rutas nunca serian cableadas sino configurables:
private static final Strirlg FILE NAME = "C:/current product.ser"; private static final String CARRIER = "State Express"; private static firlal int LOADING DOCK = 1; public static vczid main(String[l args) ( try i
C o n t e x t F r i i p e r t i e s F a c t o r y factory = new C o n t e x t F r o p e r t i e s F a c t o r y ( ) ;

factory.makeFropertiesDefault(); FileInputStream instream = n e w FileInputStream(F1LE NAME); ObjectInputStream irj = r~ew ObjectInputStream(ir~Strearn); Handle handle = (Handle) in. readobject ( ) ; Manufacture manufacture = (Manufacture) PortableRemoteObject class); .narrow(hand1e.getEJBObject ( ) , Mar.ufactlure. System.out.println("Froduct routings:");
( ) ) { while (manufacture.hasNextRoutir~g String routir~g = manufacture.getNextRoutir~g ( ) ; System.out.prir~tln (routirTq) ;

I
System.out.prir~tlr~("Product finished; shipping.. manufacture.ship(CARRIER, LOADING DOCK); manufacture.remove();
] catch
.");

(Exception e ) { e.printStackTrace0; ) catch (Throwable t ) { t.printStackTrace( ) ;

I I Este cliente "completar fabricaci6nNreanuda el proceso alli donde lo dej6 el cliente "comenzar fabricaci6nU. Observe que nos preocupamos de eliminar el bean de sesi6n con estado del sewidor. Esto no es relevante para beans de sesi6n sin estado porque no estin consumiendo n i n g h recurso en el servidor; remove ( ) es habitualmente no operativo. Pero si no eliminamos un bean de sesi6n con estado antes de haber terminado con 61, seguiri vivo, obstruyendo la memoria (o a1 menos el almacin de pasivaci6n) del servidor hasta que conchya el plazo.

Capitulo 15
El cliente PlaceSampleOrders
El cliente "realizar pedidos de prueba" crea seis pedidos. Hemos elegido fechas de vencimiento para 10s pedidos de mod0 dos pedidos estarin atrasados, dos estarin dentro del plazo establecido y dos pedidos serin realizados con tanta antelacion que su fabricacion no debe ser planificada todavia. Esto ejercitara toda nuestra logica de empresa. Este es el c6digo:
packaqe import import import import import import impart import import public factory. clients; .j a v a . r m i . R e m o t e E x c e p t i o n ; j a v a x . e j b. +; j a v a x . namirlq. *; j a v a x . 1-mi . P a r t a b l e R e m o t e O b j e c t ; java.util.Properties; j a v a . u t ~ i .lC a l e n d a r ; j a v a . u t i 1 .Date; f a c t o r y . manage o r d e r s .ManageOrders; f a c t o r y . m a r ~ a g e orders.ManageOrdersHome; class PlaceSamyleOrders
{

// //

O b s e r v e q u e e n ur, e n t o r n o d e p r o d u c c i 6 r 1 , S e r i a n c o n f i g u r a d o s e r ~ un a r c h i v o d e p r o p i e d a j e s p r i l r a t e s t a t i c f i r , a l i r ~ t SALES DIVISION 1 = 1 ; F ' r i v a t e s t a t i c f i n a l i n t SALES DIVISION 2 = 2; ~ ' r i v a t es t a t i c f i r l a 1 i n t SALES DIVISION 3 = 3 ; p r i v a t e s t a t i c f i r , a l i n t ORDER 1 = 1; p r i v a t e s t a t i c f i n a l i r ~ t ORDEF: 2 = 2 ; p r i v a t e s t a t i c f i n a l i n t ORDER 3 = 3 ; p r i v a t e s t a t i c f i n a l i n t ORDER 4 = 4 ; p r i v a t e s t a t i c f i r i a l i r l t ORDER 5 = 5 ; private s t a t i c ~ ' r i v a t es t a t i c prlvate static public try final final final S t r i n g PRODUCT 1 S t r i n ' q PRODUCT 2 S t r i r l g PFiOD~JCT 3
= = =

"DESKOl"; "CHAIROl"; "LAMPO1";


{

s t a t i c v ~ i dm a i n ( S t r i n g [ ] a r g s )

i
C o n t e x t P r c ) p t r t i e s F a c t r s r y f a c t o r y = rlew C s r ~ t e x t P r o p e r t i e s F a c t c t ~ ( y ) ; P r o p e r t i e s p r o p = f a c t . o r y . q e t I r ~ i t i a l C ~ r ~ t e s t P r o p e r t( i) e ; s I n i t i a l C o n t e x t i r l i t i a l = new I n i t i a l C i j r j t e x t ( p r n p i ; Object homeobject
=

i r j i t i a l . lookup ("ManageOrdersM);

ManaqeOrdersHome

home = ( M a r ~ a g e O r d e r s H o m e ) P o r t a b l e R e m o t e O b j e c t . n a r r o w ( h o m e O b je c t ,

ManageOrdersHome.class);
Marlageorders marcaqeorders
=

h,,rne. c r e a t e ( ) ;

Caler,dar calendartJotSched~llable = C a l e n d a r . q e t I n s t a n c e ( ) ; c a l e n d a r N o t S c h e d u l a b l e . add ( C a l e n d a r . D A Y OF YEAP,, 1 4 ); Calendar calendarSchedulatle


=

caleridarSchedulable.add ( C a l e r ~ d a rDAY . OF YEAR,

Calendar .getInstar~ce ( ) ; 5 );

manageOrders.pla-ieOrder(SALES DIVISIOtJ 1 , ORDER 1, PRODUCT 1 , calendarNotSchedulable.qetTime() ) ;

Beans de sesion y logica de empresa


rnanageOrders.placeOrder(SRLES DIVISION 2 ,
ORDER 1 , PRODUCT 2 , calertdari.ltitSchedulable.getTlrne ( ) ) ;

manageOrders

,p

l a c e o r d e r (SALES DIVISION

1, ORDER 2 , PRODUCT 3 , calendarSchedulable.getTime() ) ;


ORDER 2 , PRODUCT 1 ,

SALES DIVISION 2 ,

calendarSchedulable.qetTirne());
SALES DIVISION 1 , ORDER 3 , PRODUCT 2 , calendarOverdue.~~etT~rne ( ) ) ;

SALES DIVISION 2 , ORDER 3 , PRODUCT 3 , c a l e n d a r O v e r d u e . getTirne ( ) ) ;


]

catch (Excepti<~n e) { e.printStackTrace ( ) ;

Este cliente simplemente obtiene una referencia a1 EJBManageOrders y la utiliza para realizar seis pedidos. Cada pedido tiene una divisi6n de ventas, un numero de pedido, el product0 solicitado y la fecha de vencimiento.

El cliente ManagerSampleOrders
El cliente "gestionar pedidos" enumera 10s pedidos atrasados y despuks cancela el primer pedido atrasado:
package import impcrt import import import ~rnport irr~pnrt import import public factory.clients;

ja v a . rmi . R e r n o t e E x c e p t i o n ; ja v a x . e j b . + ; j a v a x . narninq. *; j a v a x . r m i .FortableRernoteObj e c t ;


java.util.Properties; factory.manage orders.MarcageOrders; f a c t o r y .manage o r d e r s .ManageOrdersHorne; f a c t o r y . m a n a g e orders.OverdueOrderVlew; f a c t o r y . manage o r d e r s . OpertOrderVlew; class ManageSampleOrders void
{ {

public try

static

main(String[] args)

1
C o n t e x t P r o p e r t i e s F a c t o r y f a c t o r y = new C o r ~ t e x t P r o p e r t i e s F a c t o r (y ) ; P r o p e r t i e s p r o p = f a c t o r y . q e t I n i t i a l C o r ~ t e x t P r ~ ~ p e r t ( i )e; s I n i t i a l C o n t e x t i n i t i a l = new I n i t i a l C o r ~ t e x ( t p r o p ];
Object homeobject
=

i n i t i a l . lookup("Manage0rders") ;

M a n a g e O r ' i e rsHome

home = ( M a n a g e O r d e rsHorne ) PortableRernoteObject. r~arrow(home0b ej c t ,

ManageOrdersHome.class);
Manageorders manageorders
=

home. c r e a t e ( ) ;

//

Enurnerar p e d i d o s a t r a s a d o s OverdueOrderView [ I overdueOrders

rnanageOrders. getOverdueOrders ( ) ;

Capitulo 15
for (irit iter = 0; iter < overdueOrders.length; itertt) { OverdueOrderView overdueorder = overdueOrders [iter] ; S y s t e m . o u t .println ( "Product " + overdueOrder.product t " is due o n " + overdueOrder.dateDue t " . It's status is " t overdueOrder.status t " . " I ;
1

/ / Cancelar el primer pedido atrasado if (overdue0rders.length > 0) { OverdueOrderView overdueorder = overdueOrders[O]; System.out .println("About t o cancel a n order.. . " ) ; try i mar~ageOrders.cance10rder(0verdueOrder.salesDivisior1, overdueOrder.orderNumber); System.out .println ("Car~celed order for " t overdueOrder.product. trim( ) + " . " ) ; 1 catch (factory.manage orders.NoSuch0rderException n s a e ) { System.out.prir~tln("Fai1ed to firld o r d e r . " ) ; 1 catch (factory.order.OrderNotCar~ce1ab~eExceptior once) { System.out .println ("Cannot cancel a n order in production." 1

) ;

1
catch (RemoteException r e ) { re. p r i n t S t a c k T r a c e ( ) ; 1 cat-ch (NamingException ne) ( ne.printStackTrace ( ) ; } catch (CreateException c e ) { ce.printStackTrace ( ) ;
}
I

El cddigo es bastante sencillo de comprender. Fijese en la e x c e p c i 6 n 0 r d e r ~ o t ~ a n c e l a b l e ~ x cie op nt. Esta es la expresidn de una regla de empresa en el sewidor que no permite la cancelacidn de pedidos una vez iniciada la produccidn. La excepcidn que genera en su 16gica de empresa es automiticamente enviada a1 cliente, a menos que se trate de una excepcidn Runt i m e E x c e p t i o n o de un error. Idealmente, nuestro cliente deberia indicar si una operacidn tendria kxito antes de ser emprendida. Por ejemplo, el b o t h o el elemento del men6 podria estar destacado en gris. Obviamente, se requeriria un enfoque mis creativo para un navegador Web o para clientes mdviles (telkfonos WAP, PDA, etc.). En cualquier caso, esta excepcidn indicari quk regla ha sido violada y perrnitiri informacidn retroactiva para el cliente.
El cliente CreateProducts

Finalmente, el cliente que crea algunos productos de muestra:


package import import import import import import import public factory.clier1ts;

java.rmi.RemoteException; j avax. ejb. * ; j avax. naming. ; javax. rmi. PortableRemoteObject; java.uti1. Properties;
factory.manage orders.ManageOrders; factory .manaqe o r d e r s .ManageOrdersHome; class CreateProducts {

Beans de sesion y logica de empresa

public s t a t i c void main(String[] args) { try t C o n t e x t P r o p e r t i e s F a c t o r y f a c t o r y = new ContextPropertiesFactory( ) P r o p e r t i e s p r o p = f a c t o r y . g e t I n i t i a l C o r ~ t e x t P r o p e r t i e (s1 ; I n i t i a l C o n t e x t i n i t i a l = new I n i t i a l C o n t e x t ( p r o p ) ; Object homeObj e c t
=

i r l i t i a l . lookup ( "ManageOrders") ;

ManageOrdersHome

home = ( M a n a g e O r d e r s H o m e ) PortableRemoteObj e c t . r ~ a r r o w ( h o m e o b je c t ,

ManageOrdersHome.class);
ManageOrders manageOrders
=

home. c r e a t e ( ) ;

1 catch

(RemoteException r e ) re.printStackTrace ( ) ; ] c a t c h (NamingException n e ) ne.printStackTrace(); 1 catch (CreateExceptinn c e )


C e . F,L-lr!Kit FiCkTr,3<:P [ ) ;

{
{

El cliente C r e a t e p r o d u c t s es otro sencillo fragmento de c6digo; obtenemos una referencia a1 EJB M a n a g e O r d e r s y le indicamos que Cree algunos productos de prueba.

Implementation del bean de sesion sin estado


Nuestro bean de sesion sin estado de la aplicaci6n de p r u e b a , ~ a n a g e ~ r d e rtiene s , la principal clase de i m p l e m e n t a c i 6 n f a c t o r y . m a n a g e - o r d e r s . M a n a g e O r d e r s E J B . Hemos divididoestaclase en secclones:
0

Mktodos de empresa

O Mktodos de ayuda de implementaci6n O Mktodos de ciclo de vida y de sistema


Ademis, veremos en esta secci6n el c6digo para otra clase: P r o d u c t C r e a t i o n H e l p e r . Esta clase regular Java nos asiste en nuestra implementaci6n.

Metodos de empresa
Los mktodos de empresa irnplementados en esta clase corresponden a 10s mktodos de empresa declarados en la interfaz remota del bean. Se corresponden basindose en una convenci6n: tienen el mismo nombre y firma de mktodo. Observe que n o generamos una excepcion j a v a r m i .R e m o t e E x c e p t i o n desde ningun mktodo de

implementation. E s t i permitido per0 es un comportamiento lamentable. En general, el desarrollador de


bean debe generar una excepcion de aplicaci6n para indicar un error de logica de empresa y un E J B E x c e p t i o n para indicar un error de sistema de algun tipo. Examinemos primer0 10s mktodos de empresa:

Capitulo 15
package impcrrt import irnF'crt import import impcrrt import irnpiirt import import import import import import impcrt import public f a c t o r y . manage o r d e r s ; javax.ejb.+; j a v a x . naming. +; j a v a x . rmi. Portablek!trr~oteObj ect;

]ava.rmi.RemoteEuception:
java.uti1 java.uti1 j ava. u t i l java.uti1 .Date; .Collection; . Iterator; .LinkedList;

factory.order.OrderHome;
factory.order.Order; f a c t o r y . o r d e r . OrderPK;

factory.order.StatusStrir~gs; factory.product.Product;
f a c t o r y . p r o d u c t . ProductHorne; factory .product. Routir~qIr~structior~; factory. order. O r d e r P J , 2 t C a r 1 c e p t i o r 1 ; class ManaqeOrdersEJB final int implements SessionBean
=

private

static

MILLIS-IN-DAYS

86400000;

El m k t o d o p l a c e o r d e r ( ) hace uso de nuestros dos beans de entidad de muestra, O r d e r P r o d u c t . Este mktodo invoca dos mktodos de ayuda, g e t P r o d u c t H o m e ( ) y g e t O r d e r H o m e ( ) . Estos encapsulan el acceso JNDI a las interfaces iniciales y serin examinados brevemente en la siguiente secci6n:
//
M&to'ios d e empresa p u b l i c v o i d p l a c e O r d e r ( i r 1 t s a l e s D i v i s i o n , i n t crderNurnber, S t r i n g pruductNarne, D a t e d a t e D u e ) throws NoSuchProductExceptim, DuplicateOrderException

//

Encontrar e l pruducto ProductHome producttiome = g e t P r o d u c t H o m e ( ) ; P r o d u c t p r o d u c t = p r e d u c t H o m e . f i n d B y P r i m a r y K e y [ p r ~ i d u c t N a m e; )

//

c r e a r e l peJldo OrderHorne o r d e r H o m e = g e t 0 r d e r H a m e ( ) ; o r d e r H o m e . c r e a t e [ s a l e s D i v i s i o n , crrderNumber,

product,

dateDue);

1 catch
]

(NamirlgException n e ) { t h r o w new E J B E s c e p t i o n ( n e ) ; c a t c h (RemoteException r e ) { t h r o w new E J B E x c e p t i o n ( r e ) ; catch (FirderException f e ) { i f ( f e instanceof ObjectNotFoundException) t h r o w new N o S u c h P r o d u c t E x c e p t i o r ~ ( ) ; 1 else { t h r o w new E J B E x c e p t i o n ( f e ) ;
I

1 catch
if
)

(CreateException c e ) { [ o r d e r E x i s t s ( s a l e s D i v i s i o n , orderNurnber) ) t h r o w new D u p l i c a t e O r d e r E x c e p t i n n O ; else { t h r o w new E J B E x c e p t i o n ! c e ) ;

Beans de sesion y logica de ernpresa


Es conveniente considerar c6rno 10s problernas de 16gica de ernpresa dictan respuesta a1 manejo de F i n d e r E x c e p t i o n y C r e a t e E x c e p t i o n . Si la excepci6n del buscador es un resultado delproducto que n o es encontrado en la base de datos, se envia una excepci6n cornprobada a1 cliente, N o S u c h P r o d u c t E x c e p t i o n . Si la exception del buscador se debe a otra causa indeterminada, se genera en su l u g a r ~ ~ ~ ~ x c e p (el t cliente i o n recibiri una excepci6n ~ e m o t e E x c e p t i o n )Existe . un patr6n similar a C r e a t e E x c e p t i o n , aunque necesitarnos utilizar la funci6n de a y u d a o r d e r ~ x itss ( ) para deterrninar l a c a u s a c r e a t e E x c e p t i o n . El metodo de ernpresa c a n c e l o r d e r ( ) n o introduce nada nuevo. La excepci6n OrderNotCancelableException se genera desde el metodo de ernpresa correspondiente del pedido cancelorder () :
publlc void c a n c e l O r d e r ( i r t t s a l e s D i v i s i o n , i n t orderNurnber) throws NoSu~hOrderException, OrderNotCar~celableException {

//

Erlcoritrar e l p e d i d o OrderHome o r d e r H o m e = g e t 0 r d e r H c m e ( ) ; O r d e r P K o r d e r P K = new O r d e r P K ! s a l e s D i v i s i o n ,

orderNurnber) ;

// Can~elarlo
O r d e r o r d e r = orderHorr1e.flrcdByPr1maryKey!orderPK); o r d e r . c a r ~ c e l o r d e (r ) ;
]

1
]

c a t c h (Namir,gEnception n e ) [ t h r o w new E J B E x c e p t i o n ( n e ) ; c a t c h ( P e r r ~ f > t e E x c e p t i o rr ie) { t h r o w new E J B E z c e p t i o n ( r e ) ; catch !EirderException f e ) [ if ( f e instarlcenf Obj e c t N o t E o u n d E x c e p t i o n i t t ~ r o w new N o S u c h O r d e r E x c e p t i o r ~ ( ) ; ] else { t h r o w new E J B E x c e p t i o n ( f e );

Los rnCtodos de e r n p r e s a g e t o v e r d u e ( ) y g e t S c h e d u l a b l e O r d e r s ( ) estin integrados en la funcionalidad ofrecida por 10s rnCtodos iniciales del bean de e n t i d a d o r d e r , f i n d U n c o m p l e t e d O r d e r s ( ) y f i n d O p e n O r d e rs ( ) . Los rnCtodos de ernpresaaplican entonces reglas de ernpresa adicionales para proteger las colecciones devueltas de 10s rnitodos buscadores. Varios metodos (tiempo de producci6n y tiernpo rnixirno de inventario) proceden de mCtodos de ayuda que serin explicados en la siguiente secci6n:
public try OverdueOrderView[] getOverdueOrders() {

i
L i n k e d L i s t o v e r d u e o r d e r s = rlew L i n k e d L i s t ( ) ; D a t e t o d a y = r,ew D a t e ( ) ; l o n g t o d a y M i l l i e = t o < j a y . g e t T i m e( ) ; l o n g 1 e a d T i m e M i i l i s = g e t L e a d T i m e D a y s ( ) + MILLIS I N DAYS; OrderHome orderHorne = g e t 0 r d e r H o m e ( ) ; C o l l e c t i o n uncompletedOrders = ~3rderHornef . indUncompleted0rders ( ) ; I t e r a t c - ~ riterUncornpleted0r-ders = uncorrpletedorders. i t e r a t o r ( ) ;

Capitulo 15
Order uncompletedOrder = (Order) PortableRemoteObject . narrow(iterUncomplet.ed0rders .next ( ) , Order. class) ; Date dateDue = uncornpletedOrder. getDateDue ( ) ; String status = uncompletedOrder. getstatus ( ) ; long dueDateMillis = dateDue.getTime ( ) ; if ((status.equals(StatusStrir~gs.OPEN) && (todayMillis + 1eadTimeMillis > dueDateMillis) ) I I (status.equals(StatusStrir~gs.IN PROCESS) && (todayMillis > dueDateMillis) ) ) [ OverdueOrderView view = new OverdueOrderView(ur~completedOrder .getSalesDivision( 1 , uncompletedorder .getOrderNurnber ( ) , uncompletedOrder .getProductOrdered().getName(), status, dateDue); overdueOrders.add(view);

I
I
OverdueOrderVlew[] overdue = new OverdueOrderView[overdueorders.size()]; return (OverdueOrderView[l ) overdueOrders.toArray(overdue);
]

catch (NamingException n e ) 1 throw r~ew EJBException ( n e ); 1 catch (RemoteException re) { throw new EJBException ( r e ) ; ] catch ( FinderException fe) { throw new EJBException ( f e ) ;

I
1

LirikedList schedulableOrders = new LinkedList ( ) ; Date today = new Date( 1 ; long todayMillis = today.getTime ( ) ; long maxInventoryTimeMillis = g e t M a x I n v e r 1 t o r y T i m e D a y s ( ) * MILLIS IN DAYS; MILLIS IN DAYS; long 1eadTimeMillis = getLeadTimeDays ( ) OrderHome orderHome = getOrderHome ( ) ; Collection openorders = orderHome. findOpenOrders ( ) ; Iterator iterOpenOrders = o p e n O r d e r s . i t e r a t o r 0 ;
+

w h i l e (iterOpenOrders.hasNext()) { Order openorder = (Order) PortableRemoteObject.r~arrow(iterOper~Orders.r~ext(), 0rder.class); Date dateDue = openorder. getDateDue ( ) ; long dueDateMillis = dateDue.getTime ( ) ; if (todayMillis >= dueDateMillis - 1eadTimeMillis - maxInventoryTimeMillis) { Oper~OrderView view = new OpenOrderView(open0rder.getSalesDivision ( ) , openOrder.get0rderNumber ( ) , openOrder.getProductOrdered().getName~), d a t e D u e ); schedulableOrders.add(view);

1
1

Beans de sesion y logica de empresa

OpenOrderView[] s c h e d u l a b l e = new OpenOrderView[schedulab1eOrders.size()]; r e t u r n ( O p e r i O r d e r V i e w [ l ) schedulableOrders.toArray(schedu1ab1e);

I
]

catch throw catch throw catch throw

(NamingException new E J B E x c e p t i o n (RemoteException new E J B E x c e p t i o r j ( Fir~derExceptior~ new E J B E x c e p t l o n

Los metodos de e m p r e s a c r e a t e P r o d u c t ( ) y a d d R o u t i n g I n s t r u c t i o n ( ) son para ser utilizados por la interfaz Web. Ambos hacen uso de beans de entidad. El metodo c r e a t e p r o d u c t ( ) toma el I D y el nombre del producto como parimetros, utilizindolos para crear un bean de entidad con una lista vacia de instrucciones de redireccionamiento. El bean de entidad del producto insertari un registro correspondiente en la base de datos. Despues de que el producto haya sido creado, el metodo a d d R o u t i n g I n s t r u c t i o n ( ) puede ser utilizado para ahadir instrucciones de redireccionamiento correspondientes, una cada vez:
public void createproduct (String id, S t r i r ~ g name)
{

ProductHome productHome = g e t P r o d u c t H o m e ( ) ; p r o d u c t H o m e . c r e a t e ( i d , name, rlew R o u t i n g I r ~ s t r u c t i o n [I

} ) ;

1 catch 1
]

throw catch throw catch throw

(Namir~gExceptionn e ) { new E J B E x c e p t i o n ( n e ) ; (CreateException c e ) { new E J B E x c e p t i o n i c e ) ; (RemoteException r e ) { new E J B E x c e p t i o n ( r e );

I
1
public void
addRoutirtgIrlstruction(Strirlg i d , i n t sequence, String instruction) {

try

ProductHome pro~IuctHome = g e t P r o d u c t H o m e ( ) ; P r o d u c t p r a d u c t = p r o d u c t H o m e . f i n d B y P r i m a r y K e y ( i d ); product. addRoutir~gIr~structio (s re ~q u e r , c e , i n s t r u c t i o n ) ;

1 catch 1
)

throw catch throw catch throw

(FinderException new E J B E x c e p t i o n (NamingException new E J B E x c e p t i o n (RemoteException new E J B E x c e p t i o n

fe) [ ( f e ); ne) [ ( n e ); re) { ( r e );

I
El metodo de empresacreateSampleProducts ( ) existe hicamente para iniciar la aplicaci6n de muestra, pero hay una funci6n que merece la pena analizar: su implementaci6n esti en una clase de ayuda:
public void createSampleProducts()
[

try ProductHome productHome


=

getProductHome (

) ;

/ / Crear tres productos d e prueba ProductCreationHelper pch = n e w ProductCreatior~Helper(productHome); pch.createAl1 ( ) ;


)

catch (NamingException n e ) I S~L-ow n e w EJBException ( n e ) ;

I
En general, esta clase de ayuda es idkntica a la principal clase de implementaci6n desde el punto de vistade la especificaci6n, en lo que se refiere ?limitaciones y privilegios de EJB. Todavia no podemos crear hilos, ni acceder a1 sistema de archivos, etc. Este es el caso de ProductCreationHelper,que emprende acciones que podrian haber tenido lugar en linea de una forma igual de sencilla:
package factory. manage o r d e r s ;

i m p o r t j avax. ej b. EJBEzception; import factory. product. PL-oduct; import factory.product.ProdllctHume; import f a c t o r y .product. R o u t i r ~ g I r ~ s t ~ u c t i o n ; import factory.product.NoSuchRouting1nstruction; public c l a s s ProductCreationHelper { ProductHome productHome; public ProductCreatior~Helper(ProductHome productHome) [ this.productHome = productHome;
I

public void

createAll()

try i createDesk ( ) ; createchair ( ) ; createlamp ( ) ;


}

catch (Ezception e ) { e. p r i n t S t a c k T r a c e ( ) ; t h r o w n e w EJBException ( e );

public void createDeslr [

throws Exception [
=

n e w RoutingInstructior1(5, "Compress the wood.") ; RoutingInstruction stain = new RoutinqInstruction(10, "Stain the wood."); RoutingInstruction assemble = n e w RoutingIr~struction(l5, "Assemble rhe desk."); RoutingInstruction[] routinqs = n e w RoutinqInstruction[] { compress, stain, assemble I; productHome .create ("DESKOl", "Compressed Wood Desk", routir~qs) ;

Routir~.jInstruction compress

Beans de sesion y logica de empresa

public

void

createchair ( 1

throws
=

Exception new

RoutingInstructior~ (5, "Extrude p l a s t i c . " ) ; Routir~qir~struction g l u e = new R o u t i r ~ g I r ~ s t r ~ ~ c (1 t i0o ,n ; " G l i ~ et ~ g e t h e r . " ) R o u t i r ~ g I r ~ s t r u c t i opr a ~i n t = rlew R o u t i r ~ q I r ~ s t r u c t i o r ~ ( l 5 , " S ~ , r a y p a i r ~ t 1. ; " Routir~gInstructior~[r ] o u t i n g s = new R c u t i r l g I r ~ s t r u c t i o r ~ [ { ] extrude, glue, paint

R o u t i r ~ g I r ~ s t r u c t ie ~x nt r u d e

I
1

p r r ? d u c t H o m e . c r e a t e ("CHAIR01",

"Quality

Plastic

C h a i r " , r o u t l r ~ g s; )

public

void

createlamp(]

throws
=

Exceptiorl rlew

R o u t i r ~ g I r ~ s t r u c t i(~ 5m , "Get b u l b frcm i n v e n t o r y . " 1 ; R o u t i r ~ g I n s t r u c t i o n g e t l a m p = new R o u t i r ~ g I n s t r u z t i o n (10, y ). ; "!;et l a m p f rorn i r ~ v e r ~ t o r " R o u t i n g I n s t r u c t i o n s c r e w T o g e t h e r = new R o u t i r l q I r l s t r u c t i o r 1 ( 1 5 , "Screw t o g e t h e r . " ) ; R o u t i r ~ g I r i s t r u c t i o n f r a y c o r d = r ~ e w Routir1gInstructior~(20, "Pre-fray t h e cord"); RoutingIristr~uctiiln [ I r o u t i r ~ g s = new R o u t i n g I r ~ s t r u c t i [~I r [ g e t B u l b , getLanip, s c r e w T o g e t h e r , f r a y c o r d

RolutirlgIrlstructior~ getBulb

Product try
]

lamp

prod1uctHome.create("LAPIFO1", " C u s t o m Made


r~utir~gs);

L,ampW,

i
l a m p . d e l e t e R o u t i n q I r ~ s t r u c t i o r(~ 2 1) ; c a t c h (NoSuchRoutingInstructior~rtsri 1 1amp.deleteRoutingIr~structio( r2 ~ 0 );
[

Considerernos ahora un caso excepcional. Supongarnos que hernos decidido que nuestros EJB necesitan ejecutar una acci6n prohibida por la especificaci6n y nuestro actual servidor de aplicaci6n apoyari este cornportarniento. Si nuestro servidor de aplicaci6n aplica las restricciones de EJB, lo hari utilizando el rnodelo de seguridad de Java. Quizis necesiternos sobrepasar las limitaciones de seguridad de Java bajo las cuales se ejecuta nuestro bean y que estin destinadas a proteger a1 servidor de operaciones inseguras o potencialrnente perjudiciales. (Esto n o significa que saltemos 10s controles de acceso sobre EJB, que es un sisterna completarnente diferente.) Necesitarernos utilizar una clase de ayuda junto a una llamada
doprivilege

0.

La seguridad Java esti ligada a1 cargador de clase. Con la rnayoria de servidores de aplicaci6n, nuestros EJB serin cargados por uno (o rnis) cargador(es) de clase y el servidor de aplicaci6n tendri un cargador de clase diferente que utiliza para las clases de su ruta de clase. Para evitar la seguridad y ejecutar la operaci6n no portitil, pondrernos nuestra clase de ayuda en la ruta de clase y realizarernos la llamada autorizada. La seguridad Java y su relaci6n con el cargador de clase y la llarnada d o p r i v i l e g e d ( ) es una funci6n estindar (quizis algo esotirica) del lenguaje Java. Consulte una referencia del lenguaje en http:// java.sun.com/j2se/l.3/docs/api/index.htrnl si necesita rnis inforrnaci6n. Corno norrna, a rnenos que tenga un buen rnotivo, no haga esto. Afectari a la portabilidad de 10s cornponentes que escriba.

Capitulo 15
Metodos de ayuda de implementaci6n
Continuando con nuestra implementaci6n d e ~ a n a g e ~ r d e rafiada s ~ ~este ~ , c6digo a1 codigo anterior:
//
Ayudant.es d e i m p l e m e n t a c i 6 n p r i v a t e booleari o r d e r E x i s t s ( i n t s a l e s D i v i s i o n , irit orderNurnber)
{

try I OrderHome orderHorne = g e t O r d e r H o m e 0 ; O r d e r P K o r d e r P K = new O r d e r P K ( s a l e s D i v i s i o n , o r d e r N u m b e r ) ; O r d e r o r d e r = o r d e r H o m e . f i n d B y P r i r n a r y K e y ( o r d e r P K ); return true;


}
1

catch (Exception e ) return false;

p r i v a t e i n t getLeadTimeDays ( ) throws Namir~gExceptiort { I r ~ i t i a l C o n t e x t i n i t i a l = new I n i t i a l C o n t e x t ( ) ; I n t e g e r 1eadTimeDays = ( I n t e g e r ) initial.lookup("java:comp/env/lead return 1eadTimeDays. i n t V a l u e ( ) ;

time");

p r i v a t e i n t qetMaxInventoryTimeDays ( ) throws Namir~gException { I n i t i a l C o n t e x t i n i t i a l = new I n i t i a l C a n t e x t ( ) ; I n t e g e r inventoryTimeDays = ( I n t e g e r ) i n i t l a l . lookup("java:cornp/env/max i n v e n t o r y t i m e " ) ;

/ / Un a p u n t a d o r n u l o d e s h a r a l a t r a n s a c c i 6 n r e t u r n inventoryTimeDays. i n t V a l u e ( ) ;

I
p r i v a t e ProductHome g e t P r o c l u c t H ~ m e ( ) t h r o w s NamingException I n i t i a l C o n t e x t i n i t i a l = new I n i t i a l C o n t e x t ( ) ; ProductHome home = ( P r o d u c t H o m e ) javax.rmi.PortableRemote0bject n a r r o w j i n i t i a l . l o o k u p ( "j a v a : c o m p / e r ~ v / e j b / P r o d u c t " ) , ProductHome.class); r e t u r n home;
{

I
p r i v a t e OrderHome g e t O r d e r H o m e ( ) t h r o w s N a m i n g E x c e p t i o n { I n i t i a l C o n t e x t i n i t l a 1 = new I n l t i a l C o n t e x t ( ) ; OrderHome home = (OrderHome) j a v a x . rmi. PortableRemoteObject . n a r r o w ( i n i t i a l .lookup("java:comp/er~v/ejb/Order"), 0rderHome.class); r e t u r n home;

Observe que, mientras que 10s metodos de empresa accesibles a traves de la interfaz remota deben ser todos pbblicos, estos mitodos de implementacidn pueden ser declarados privados. El primer metodo, o r d e r E x i s t s ( ) ,ha sido referenciado con anterioridad y es bastante autoexplicativo. La interfaz inicial del bean de entidad del pedido se utiliza para encontrar un pedido pre-existente con la misma clave. Si se encuentra uno, se devuelve el valor t r u e ; de n o ser asi, se devuelve f a l s e , indicado por una excepci6n. Los dos siguientes mktodosde ayuda de implementaci6n recuperan 10s parimetros de tiempo de producci6n ( g e t L e a d T i m e D a y s ( ) ) y el tiempo de inventario miximo

Beans de sesion y Iogica de empresa


(getMax1nventoryTimeDay.s ( ) ) desde el entorno J N D I del bean. Esta informaci6n de s610 lectura esti especificada en el descriptor de implementaci6n del bean. Es menos flexible que almacenar la informaci6n en la base de datos, obviamente (donde seria almacenada en una aplicacidn real de fabricaci6n). Para modificar esta informaci6n, encontrada en el descriptor de implementaci6n, necesitariamos volver a desplegar el bean sobre nuestro sewidor de aplicaci6n. Sin embargo, almacenar la informaci6n en el descriptor, como hacemos aqui, es mls flexible que refundir valores en el c6digo. Para modificar la informaci6n de codigo, necesitariamos reconstruir el bean y volver a implementarlo.

En general, el tip0 de informaci6n que pertenece a1 entorno del bean es informaci6n personalizada que es poco probable que resulte volitil para una determinada implementaci6n. Buenos candidatos podrian ser el nombre de la compaiiia, instrucciones SQL para el acceso direct0 a base de datos o una direccidn I P de un sewidor de aplicaci6n ERP. U n muy ma1 candidato seria el tipo de cambio entre el Euro y el Dolar. Las entradas de entorno pueden ser de cualquiera de 10s siguientes tipos: st r i n g , B o o l e a n , B y t e , S h o r t , I n t e g e r , Long, F l o a t y D o u b l e . Estas entradas son especificadas normalmente utilizando una herramienta proporcionada por el vendedor de nuestro sewidor de aplicaci6n. El formato del descriptor de implementaci6n XML puede ser editado manualmente, si asi lo desea. Las entradas de muestra del entorno de aplicaci6n para el bean de "gestionar pedidos" tienen este aspecto:

<env-entry>

<env-entry-rtame>max-ir~ventory t i m e < / e n v - e n t r y - n a m e ? < e n v - e n t r y - t y p e > j a v a . larlg. Ir,tGger</env-eritry-type>


<env-entry-value>lO</er~v-er~try-value> </er~v-entry>

Los nombres que especificamos para nuestras variables de entorno (con el elemento < e n v - e n t r y name>) estarin disponibles para nuestro bean en el context0 " j a v a : comp. / e n v / " . VCase el c6digo para un ejemplo de esta asociaci6n. Los dos siguientes mktodos de ayuda de implementation recuperan las interfaces iniciales de 10s dos EJB de entidad que son referenciados por este EJB ( O r d e r y ~ r o d u c t ) El . desarrollador de bean declara 10s nombres 16gicos de 10s beans que referencian en el descriptor de implementation, como hemos descrito anteriormente. Estas son las declaraciones para el EJB "gestionar pedidos" de la aplicaci6n de muestra:
< e jb-ref'. < e j b - r e f - r ~ a m e > eb j / O r d e r < / e j h-ref-riame; <ejb-1-ef - t y p e ' . E r ~ t i t y C / e j b - r e f - t y p e >

<homeifactory.ol-der.OrderHome</home> <remote?factol-y.order.Order</remote>
<ejb-lir~k'.Ol-dersc/ejb-link> < / e jb-ref i

<ejb-ref> c e j h-ref-nameiej b / P r o d u c t < / e j b-ref-name>

Cejh-ref-typeiEntity</ejb-ref-type>
<home>fa c t d r y . p r o d u c t . P r o d ~ u c t H c ~ m e < / h o m e >

<remote>factory.product.Prcrduct</remotei
< e jb-linb:>Product</ejb-link> </ejb-ref>

Como hemos mencionado anteriomente, la entrada e j b - l i n k es opcional y el desarrollador de bean la puede utilizar para garantizar que se mantiene constante el espacio de nombre determinado. En este caso

Capitulo 15
dice "Cualquier que sea el nornbre que de a mi bean P r o d u c t o O r d e r en el espacio de nornbre JNDI, necesita utilizar el rnisrno nombre para vincularlo a la referencia e j b / P r o d u c t o e j b l o r d e r " .

Metodos de ciclo de vida y de sistema


Los rnetodos de ciclo de vida estin todos vacios. Para rnis inforrnaci6n sobre su prop6sit0, consulte la explicaci6n anterior en este capitulo:
//
Mktodos void void void de sisterna de
{

y c i c l o de

vida

public public public

ejbCreate0

1
{

ejbActivate ( ) ejbpassivate ( ) e j bRemove


( )

1
{ ]

~ ~ u b l i vc oid public i void

{ )

s e t S e s s i o r l C o r l t e x t ( S e s s i o r ~ C o n t e x tc t x )

lmplementacion del bean de sesion con estado


Nuestro bean de sesi6n con estado de la aplicacion de rnuestra,Manyf a c t u r e , tiene la clase principal de que crearemos en irnplernentaci6nf a c t o r y .manuf a c t u r e .Manu a c t u r e E J B . Esta es la ~inicaclase esta secci6n. Examinaremos dos nuevas ideas en este c6digo: como utilizar conexiones de base de datos y c6mo recuperar variables de entorno. A diferencia del bean de sesi6n sin estado analizado anteriormente, el b e a n ~ a n u a f c t u r e rnantiene el estado:
package irnpurt j a v a x . e j b . ' ; import j a v a x . naming. + ; i m p i . r t j a v a . r m i .R e m o t e E x c e p t i o n ; impart java.sq1.Connectinn; i m ~ j o r t j a v a . s q l . SQLExceptiort; i m p o r t java.sql.PreparedStatement; import javax.sql.DataSource; import java.util.Arrays; irn~.ortj a v a . u t i l . L i s t ; i m ~ > o r tj a v a . u t i l . C o l l e c t i , n s ; import j a v a . u t i l . 1 t e r a t o r ; import j a v a . u t i l . U a t e ; i m p i r t factory.product.Product; i m p ~ ' r tf a c t o r y . p r o d u c t . ProductHorne; impr3rt f a c t u r y . o r d e r . O r d e r ; i m p c ~ r t f a c t o r y . order.OrderHome; i mp c>r t f a c t o r y . u r d e r . O r d e r P K ; import f a c t f i r y . o r d e r . S t a t u s S t r i r ~ g s ; i m p o r t f a c t o r y . manage o r d e r s .OpenOrderView; import factory.manaqe orders.Manaqe0rders; i m p o r t f a c t o r y . manage o r d e r s .Marlageorder.-Hrime; i m p o r t f a c t o r y .manage o r d e r s . N o S u c h O r d e r E x c e p t i o r ~ ; i m p ~ ~ rfta c t o r y . p r o d u c t . R o ~ ~ t i n q I r ~ s t r u c t i i ~ n ; pub1 i c class ManufactureEJB implemerlts SessiorlBearl

Beans de sesion y Iogica de empresa

/ / Propiedades p u b l i c S t r i r l q mar~uf actureCe11ILi; public List routirjgIr~structi~>r~s; p u b l i c irlt currerltPositic>r~; public i n t l a s t Position;
public public public boolean orderselected; i n t seltctedSalesDivision; i n t selectedOrderNumber;

La v a r i a b l e m a n u f a c t u r e c e l 1 1 ~ se configura en la llamada e j b C r e a t e ( ) . A diferencia de la llamada e j b C r e a t e ( ) del bean de sesi6n sin estado, ksta tiene una correspondencia exacta con una llamada r e a t e ( ) realizada por el cliente sobre la interfaz inicial del bean. Observe que tambikn c ~ r r e s ~ o n d i e nc te utilizamos e j b C r e a t e ( ) como un constructor para inicializar o r d e r s e l e c t e d . Analizaremos este mktodo a continuaci6t1, junto con 10s otros mktodos de ciclo de vida (vacios):
//
M k t ~ d o sde c i c l o de vida y de sistema ~ , u b l i cv o i d e j b C r e a t e ( S t r i n g m a n u f a c t u r e C e l l I D ) t h i s . m a n u f a c t u r e C e l l I D = manuf a c t u r e C e l l I D ; ~ ' r d ? r S e l e c t e d= f a l s e ;
{

public

v,-,id s e t S ? s s i o n C o r , t e x t ( S e ~ s i o r ~ C c ~ r ~ r t etx ~ t ) [ }

A continuaci6n,1os mktodos de empresa:


//
Mktodos d e e m p r e s a p u b l i c Oper~OrderView [I try ManageOrdersHome homeManaqeOrtjers = getManageOrdersHome i ) ; Manageorders manageorders = homeManaqeOrdtrs. c r e a t e i ) ; r e t u r n manageOrders.qetSched~11ab1eOrders();
)

qetOpenOrdors ( )

]
}

catch throw catch throw catch throw

(NamingException n e ) { new E J B E x c e p t i o n ( n e ) ; (RemoteException r e ) [ new E J B E x c e p t i o n ( r e ) ; (CreateException c e ) { new E J B E x c e p t i o n i c e ) ;

I
public void

selectForManufacture(ir~tsalesUivision,
throws NoSuchOrderException,

i n t o r d e r number) BadStatusException [

try i OrderHome h o m e o r d e r = g e t O r d e r H o m e ( 1 ; O r d e r P K o r d e r P K = new O r d e r P K i s a l e s D i v i s i o n , o r d e r n u m b e r ) ; Order o r d e r = homeorder. f ir~dEyFrimaryKey ( o r d e r P K ); String orderstatus = order.getStatus (1; if ( ! o r d e r S t a t u s . e q u a l s ( S t a t ~ ~ s S t r i r ~ g s ~ O )P E 1N ) t h r o w new B a d S t a t u s E ~ c e p t i i r (~ o r d e r s t a t u s1 ;

Capitulo 15
o r d e r . beginManufacture ( ) ; P r o d u c t p r o d u c t = order.getProductOrdered(); Routir~gInstruction[] productRouting = product. getRoutingIr~structior~ ( s ) ; r o u t i r ~ g 1 n s t r u c t i o r i s = A r r a y s . a s L i s t ( p r o d u c t R o u t i r ~ g; ) Collections. sort (routir~qIristructior~ ;s ) c u r r e n t P o s i t i o n = 0; lastPosition = routir~qIr~structions.size ) ( - 1; s e l e c t e d S a l e s D i v i s i o r ~= s a l e s D i v i s i o n ; s e l e c t e d O r d e r N u m b e r = o r d e r number; orderselected = true; c a t c h (NamingExcepti o n n e ) { ne.printStackTrace ( ) ; t h r o w new E J B E x c e p t i o n ( n e ); c a t c h (RemoteException r e ) { re.printStackTrace0; t h r o w new E J B E x c e p t i o n ( r e ) ; catch ( FinderException f e ) { fe.prir~tStackTrace(); i f ( f e instanceof ObjectNotFoundException) t h r o w new N o S u c h O r d e r E x c e p t i o r ~ ( ) ; ) else { t h r o w new E J B E x c e p t i o n ( f e ) ;

p u b l i c boolean hasNextRoutinq() throws i f (!orderSelected) { t h r o w new N o S e l e c t i o n E x c e p t i o r ~ ( ) ;

NoSelectionException

t
return

( c u r r e r ~ t P o s i t i o n<=

l a s t Position) ;

public S t r i n g getNextRouting ( ) throws i f ( !orderSelected) { t h r o w new N o S e l e c t i o n E x c e p t i o r ~ ( ) ;

N ~ S e l e C t i o r ~ E ~ ~ e p t{ l o r ~

1
RoutinqInstruction r i = ( RoutinqInstruction) return r i . instruction; r o u t i n g I n s t r u c t i o n s . g e t ( c u r r e r l t P o s i t i o n + + );

I
public void ship(Strir1g c a r r i e r , i n t loading dock) throws NoSelectionException {

// //
if

D i v i s i 6 n d e v e n t a s , r~limero d e p e d i d o , t r a n s p o r t i s t a , a l m a c e r ~ d e c a r g a , f e c h a cGrnpletada, f a b r i c a d o p o r (!orderselected1 t h r o w new N o S e l e c t i o n E x c e p t i o r ~( ) ; con


=

I
Connection try null;

i
con = g e t C o n n e c t l o n ( ) ; P~eparedStatement statement
=

con.prepareStatement(getShiprner~tSQLStrir~q );
s t a t e m e n t . s e t I n t (1, s e l e c t e d S a l e s D i v i s i o r ~; ) s t a t ~ r n e r ,.ts e t I n t ( 2 , s e l e c t e d 0 r d e r N u m b e r ) ;

Beans de sesion y logica de empresa


statement.setString(3, carrier); statement.setInt(4, loading dock); statement .setDate(5, new java.sq1. Date( ( n e w Date() ) .getTime( ) statement .setstring ( 6 , manufactureCellID) ; statement.executeUpdate(); statement.close(); con. close ( ) ; orderselected = false; OrderHome homeorder = getOrderHome ( ) ; OrderPK orderPK = new O r d e r P K ( s e l e c t e d S a 1 e s D i v i s i o r 1 , selectedOrderNumber); Order order = homeOrder.findByPrimaryKey(orderPK); order. completeMar~ufacture ( ) ;

) );

1 catch
}

(NamingException n e ) [ ne.printStackTrace ( ) ; throw new E JBException ( n e ) ; catch (SQLException sqle) { try i if (con ! = null) [ con.close ( ) ;

1 catch

(Exception e) {

I
sqle.printStackTrace(); throw new EJBException (sqle); 1 catch (RemoteException r e ) { throw new EJBException ( r e ) ; ] catch (FinderException fe) { throw new EJBException ( fe);
1 I

finally [ try i if (null ! = con) [ con. close ( ) ;

i
1 catch (Exception ignore)
{

I
I

El "pedido seleccionado" es indicado por dos variables que representan la clave del pedido, s e l e c t S a l e s D i v i s i o n y s e l e c t O r d e r N u m b e r . Estinconfiguradas en el metodo s e l e c t F o r M a n u f a c t u r e ( ) .Este metodo de empresa ejecuta 10s siguientes pasos adicionales:
0 Verifica que el pedido existe y que es elegible para su fabricaci6n 0
0

Configura el estado del pedido de forma que las otras celulas de fabricaci6n sean conscientes de que el pedido esti siendo elaborado Recupera las instrucciones de redireccionanamiento para el product0 solicitado, las clasifica y las almacena en una variable Configura la variable o r d e r s e l e c t e d con el valor t r u e de mod0 que llamadas de metodo posteriores en el flujo de trabajo puedan proceder

El primer paso en el flujo de trabajo que representa el b e a n ~ a n u a f c t u r e (incluso antes de seleccionar un pedido para su fabricaci6n) es obtener una lista de pedidos abiertos. La implementaci6n de este metodo de empresa es sencilla ya que dejega todo su trabajo en el EJB de sesi6n sin e s t a d o ~ a n a q e o r d e r s , analizado en la filtima secci6n. Este es un ejemplo sencillo de una arquitectura de "capa de servicios". Observe que el bean de sesi6n con estado invoca el bean de sesi6n sin estado, pero no a1 contrario.

Capitulo 15
Sipiendo la selecci6n de pedidos, el siguiente paso en el flujo de trabajo es iterar 10s redireccionamientos del producto mientras elaboramos el producto. De nuevo, es bastante sencillo. Iteramos la configuraci6n de la colecci6n en el mitodo selectForManuf acture ( ) . Observe que nos aseguramos de que se ha seguido el flujo de trabajo, comprobando la variable orderselected. Si no ha sido seguido, generamos al cliente una excepci6n de empresa para ofrecerle la oportunidad de corregir el error. Observe tambikn que estamos iterando datos desfasados. El disefio del producto puede haber cambiado durante el proceso de fabricaci6n y no se veri reflejado en la iteration. Sin embargo, esto nos viene bien: no queremos cambiar a una nueva lista de redireccionamiento a mitad de la elaboraci6n del producto. El filtimo rnitodo de empresa, s h i p ( ) ,cambia el estado de pedido para indicar que la fabricacion ha sido concluida. Lo hace utilizando el bean de entidad Order y tambien inserta un registro de envio en la base de datos. Este esti incluido como ejemplo de acceso a la base de datos directamente desde un bean de sesi6n. En primer lugar, observe de donde procede el texto SQL: del entorno del bean. El metodo de ayuda de implementaci6n getShipmentSQLString ( ) (mostrado a continuaci6n) recupera el SQL desde el descriptor de implementaci6n XML. Esto desvincula parcialmente el EJB de 10s aspectos especificos de la base de datos. Si queremos utilizar la n?isma 16gica de empresa con una estructura diferente debase de datos, podemos hacerlo, sin rescribir el bean. Este es un caso ideal para almacenar informaci6n en el descriptor de implementaci6n:

InitlaLContext i n i t i a l S t ~ - i n , ]s q l = ( S t r i r j q ) returrj sql;

= new InitlalContext(); i r l i t i a l . l(ri,l:up( " j a v a : ccrrnp/er~~~/shipmer~tSQ ;L " )

La entrada de entorno del descriptor de implementaci6n es asi:


<?rts.-er~try> . e n v - e n t r y - n a r n e > s h i p m e r ~ tS Q L < / e r , v - e r ~ t r y - r ~ a r n e ; , < e r ~ v - e n t r y - t y p e > j a v a . l3r1y. S t ~ ~ i r ~ g < / e r ~ v - e r ~ t r y - t y p e > cenv-entry-v-ilue>ir~sert i r ~ t i i s h i p m e n t s ( d i v i s i o n , v r d e r number, c a r r i e r , l o a d i n g d o c k , d a t e c n m p l e t e d , r n a r ~ u f a c t u r e db y ) v a l u e s
(?,
?,

?,

?,

?,

?)

</env-er~try-valuei </env-entry>

En la base de datos que hemos utilizado para el desarrollo, la tabla podria ser definida ask
CREATE TABLE SHIPMENTS ( D I V I S I O N I N T E G E R NOT N U L L , O R D E R NUMBER I N T E G E R NOT N U L L , CARRIER C H A R ( S O ) , L O A D I N G DOCK I N T E G E R , DATE C O M P L E T E D D A T E , M A N U F A C T U R E D BY CHAR ( 5 @ ) , P R I M A R Y KEY ( D I V I S I O N , O R D E R - N U M B E R ) ) ;

La conexion a la base de datos debe ser recuperada en circunstancias controladas. El programador del bean no puede simplemente obtener una utilizando el DriverManager de JDBC. El contenedor EJB necesita gestionar el proceso, para implementar funciones tales como gesti6n de transacciones y reserva de conexiones. El programador, por lo tanto, debe obtener un Datasource del espacio de nombre J N D I (que es una "clase factoria" para conexiones JDBC) y utilizarlo para producir una conexion. podemos ver un ejemplo en el siguiente mitodo de ayuda getconnection ( ) . Del mismo modo, mientras que un EJB esti en una transacci6n, el programador bean no esti autorizado para interferir en el contenedor invocando commit ( ) o rollback ( ) sobre la conexion. El programador de bean debe declarar en el descriptor de implementaci6n XML que va a utilizar un recurso como una conexibn JDBC. (Otros posibles recursos incluyen conexiones JSM o JavaMail.)

Beans de sesion y Iogica de empresa


Observe que esta referencia a una conexion JDBC es una referencia 16gica que seri asociada por el contenedor en el espacio de nombre J N D I . Se especificari una correspondiente conexion JDBC cuando el bean se implemente. El XML para nuestra muestra es asi:

El EJB puede dar un nombre de usuario y una contraseiia 61 mismo, per0 refundirlos en el c6digo del bean es normalmente una mala idea. En esta muestra, dependemos del contenedor para autentificar el bean para la base de datos. A1 implementar la aplicacion, podemos especificar un nombre de usuario y una contraseiia dinimicamente. (Cbmo realizar esto exactamente es especifico del servidor de la aplicacion y la documentaci6n adjunta debe ayudar.) Finalmente, 6st0s son 10s m6todos de ayuda:
/ / AyuiJante d e implemeritacihri ( ~ l r i v a t eOrderHome getOrderHome ( ) t h r o w s N a m i r ~ g E x c e p t i o r ~ I r l i t i a l C o r l t e x t i n i t i a l = new I r ~ i t i a l C o n t e x (t ) ; Or'derHome home = ( OrderHome ) j a v a x . r m i P o r t a b l e R e m , 3 t e O b je c t .r ~ a r r o w ( i n i t i a l .l o o k u p ( " j a v a : comFF/er~v/e] b / 0 r d e r 3 '1 , 0rderHome.class); r e t u r n home;

private

ManageOrdersHome getManageOrdersHome() throws NamingExce~~tion { I r ~ i t i a l C o n t e x t i r l i t i a l = rlew I n i t i a l C o n t e x t ( ) ; M a r ~ a g e O r d e r s H o r n e home = ( M a n a g e O r d e r s H o m e ) javax.rmi.PortableRem~2teObject

.r~arrow(ir~itial.looI:u~~("java:com~~/erv/ejb/Mar~ageOrders") , Manage0rdersHome.class);
home;

return

I
p i v a t e Conriectiorl g e t C o n n e c t i o n ( ) throws SQLException, NamingException { C o r i t e x t i r l i t i a l = rlew I n i t i a l C o n t e x t ( ) ; DataSource datasource = ( U a t a S o u r c e ) i r ~ i t i a l lookup("java:comp/env/jdbc/shipDB") . ; return datasource .getConnectior~ ( ) ;

1
p r i v a t e S t r i n g getShipmentSQLString ( ) throws NamingException { I r ~ i t i a l C o r i t e x t i r l i t i a l = new I n i t i a l c o n t e x t ( ) ; S t r i n g s q l = ( S t r i n g ) i n i t i a l . lookup("java:comp/env/shipmentSQL"); r e t l ~ r nsql;

I
1

El metodo de ayuda g e t c o n n e c t i o n ( ) encuentra la clase de factoria de conexion j a v a x . s q l .D a t a S o u r c e del entorno, pricticamente del mismo mod0 que recuperamos parimetros de configuracion. Desde la factoria de conexiones, recuperamos y devolvemos una conexion. Es importante comprender que 6sta no es una conexion ordinaria debase de datos. El contenedor seguramente habri envuelto esta conexion en una clase envolvente que tambi6n implemente la interfaz Connection. Podemos utilizar el envoltorio del mismo mod0 que utilizariamos la conexion subyacente,

Capitulo 15
pero cuando cerramos la conexi6n, se cierra realmente. Se queda en el entorno, preparada para completar esta transaccih o devolverla a la reserva de conexiones. La mayoria de 10s programadores aprende muy deprisa que las conexiones a una base de datos son caras de abrir y cerrar, y debe evitarlo siempre que sea posible. Aprenden a mantener cerca las conexiones, reutilizindolas en su codigo. La programacion con un sewidor de aplicacion da la vuelta a esta regla. Abrir y cerrar conexiones es barato, porque las conexiones no se abren y cierran realmente. Con un sewidor de aplicacion, lo car0 es mantener cerca una conexion (porque entonces puede ser resewada para ser utilizada por multiples beans). Es posible ocultar una conexi6n en nuestro bean para reutilizarla en multiples transacciones pero, en general, no deberia hacerlo. Obtener un recurso, utilizar ese recurso y dejar marchar el recurso. Merece la pena repetirlo: obtener un recurso, utilizar ese recurso y dejar marchar el recurso:
c i , n = g e t C o r l r ~ e c t i oir )~; Preparedstatement statement = c i , r l . p r e ~ , a r e S t a t e m e r i t(.q e t S h i p m e r i t S Q L S t r i r ~ ~ )g) ( ; s t a t e m e r l t . s e t I n t (1, s e l e c t e d S a l e s D i v i s i c r ~ ; ) s t a t e m e r ~.ts e t I r t t ( 2 , s e l e c t e d O r d e r N u m b e r ) ; s t a t e m e r ~ ts. e t S t r i r ~ c g ( 3 , c a r r i e r ) ; statemer~j. t s e t I r i t 14, l o a d i r ~ g ~ d o c l;; ) s t a t e m e r ~ .~ s te t D a t e ( 5 , rlew j a v a . s q 1 . b a t e ( ( n e w D a t e ( ) ) . q e t T i m e ( 1 1 1 ; staterr~er,t.setStrir~ (6 g, mar~~ufactureCel1ID ;) s t a t e m e n t . execute1Jpdate ( ) ; ~ t a t e m e n tc .loue ( ) ; cc,rt. c l o s e ( ) ;

Cerramos aqui la conexion (con.close ( ) ) per0 no se cierra realmente. La clase envoltorio la intercepta. Decimos "cerrar" per0 el servidor de la aplicacion oye "reutilizar". Finalmente, kstas son un par de clase de exception que necesitamos:
package public f a c t o r y . marluf a c t u r e ; class NoSelectionException
(

exten'js

Exception

public

NoSelectinnExceptior~ ( )

I
package f a c t o r y . manufacture; Exception
[

p'lblic c l a s s Ba.3StatusExceptio1~1 extends private String status;

p u b l i c BadStatusException(String this. status = status;

status)

I
public String getstatus ( ) return status;
{

En este punto, no podemos implementar y ejecutar la aplicaci6n de muestra. Necesitamos proceder a1 siguiente capitulo, donde afiadiremos beans de entidad.

Este capitdo ha analizado detenidamente 10s beans de sesi6n. ~ s t es a una revision de 10s principales puntos:

826

Beans de sesion y Iogica de empresa


0 Los beans de sesidn representan un proceso, tarea o flujo de trabajo
0 0

Hay dos tipos de beans de sesidn: con estado y sin estado Los beans de sesion con estado pueden aligerar el desarrollo de la aplicacidn en el coste de la reajustabilidad Los beans de sesidn sin estado pueden proporcionar servicios a clientes o a otros beans La vista de cliente de la funcionalidad del servidor debe ser a travks de una fachada de bean de sesidn, ocultando asi mucha de la complejidad

0 0

0 Las entradas de entorno y recursos externos pueden ser declaradas en el descriptor de implementacidn y se puede acceder a ellas a traves del espacio de nombre J N D I

En el siguiente capitulo, analizaremos mis de cerca 10s beans de entidad. En primer lugar, mostraremos por quk 10s beans de sesidn no pueden realizar la misma funcidn en su aplicacidn que 10s beans de entidad. Despuks consideraremos algunas de las ventajas de utilizar beans de entidad, especialmente en relacidn con el rendimiento. A continuacibn, analizaremos dos variaciones de beans de entidad: aquellos con persistencia gestionada por contenedor y aquellos con persistencia gestionada por bean. Veremos las ventajas y desventajas de cada clase, mientras desarrollamos dos versiones de un h i c o bean (mis o menos, como hemos hecho en este capitulo). Tambien examinaremos el ciclo de vida y las retrollamadas de contenedor de un bean de entidad, junto con algunos elementos especificos de la entidad como claves primarias, metodos buscadores y almacenamiento en memoria cache. Finalmente, completaremos y ejecutaremos nuestra aplicacidn de muestra.

Beans de entidad

persistencia

Enterprise JavaBeans de entidad representan 10s objetos entidad de nuestro rnodelo de anilisis. Pueden corresponder a conceptos del rnundo real, corno cornpradores o productos, o pueden corresponder a abstracciones, corno procesos de fabrication, politicas de ernpresa o adquisiciones de cornpradores. Es irnportante cornprender esta noci6n de representacibn. DespuCs de todo, un bean de sesi6n puede acceder a cualquier dato a1 que pueda acceder un bean de entidad. Aunque un bean de sesi6n puede acceder a datos, no puede proporcionar una representacidn orientada a1 objeto de tales datos. ?En que se diferencia un bean de entidad? iPor quC no podernos tener un bean de sesion de "cornprador" o un bean de sesi6n de "producto", corno ocurre con 10s beans de entidad? La explicaci6n bisica es sencilla, aunque 10s detalles sean cornplicados. Hernos visto anteriorrnente que el estado rnantenido por beans de sesi6n con estado es privado, en el sentido en que el cliente que esti utilizando el bean de sesi6n en ese rnornento puede rnanipular este estado. Los beans de entidad son diferentes porque su estado es alrnacenado en la base de datos; varios clientes pueden, por lo tanto, acceder a su estado sirnultinearnente. Por ello el problerna fundamental a la hora de representar un objeto con un bean de sesi6n es c6rno poner el estado a disposici6n de 10s clientes de ese bean. U n bean de entidad es a1 fin y a1 cabo un unico punto de acceso para esos datos: cualquier cliente que acceda a 10s datos pasari por ese bean de entidad. U n bean de entidad, por otro lado, s61o es accesible a un unico cliente. Si hay rndtiples clientes, habri rndtiples beans de sesi6n. En este capitulo:
0

Cornpararernos y contrastarernos el uso de un bean de entidad con el uso de beans de sesi6n Cornpararernos y contrastarernos beans de entidad cuyo rnecanisrno de persistencia estC gestionado por contenedores y aquellos cuyo rnecanisrno de persistencia estC gestionado por el desarrollador del bean Aprenderernos corn0 desarrollar beans de entidad (versi6n persistente gestionada por contenedor y versi6n persistente gestionada por bean) C0rn~1etarerno.s nuestra aplicaci6n de fabrication del dtirno capitulo

0 0

Capitulo 16

lPor que no utilizar beans de sesion?


Para comprender la diferencia entre beans de entidad y beans de sesibn, consideremos c6mo podriamos intentar que 10s beans de sesi6n desempeiiarin el mismo papel que 10s beans de entidad en la representaci6n de un objeto, como un comprador. Intentaremos construir un bean de entidad a partir de partes de bean de sesi6n y despuks consideraremos las limitaciones de lo que hemos hecho.

Utilizar un bean de sesion con estado


Primero, intentemos utilizar un bean de sesi6n con estado. Para un comprador, podriamos escribir una clase bean similar a ksta:
public class Customer implemer~ts SessionBean private irlt customerID; private Strirq customerName; private String customerAddr; private String city; private String state; private String pustalcode; public void ejbcreate(Strir,q customerID) { thls. customerID = customerID;
{

I
public void setCustomerName (String customerName) this.customerName = customerName;

I
public String getCustomerName( ) returrt customerName;
{

1
//
. . . Metodos

sirnilares

..
( )

public void

saveStateToDatabase

public void

loadStateFromDatabase(i

//

.. . c6digo sql . . .

1
//

. . . M e t o d ~ s d e ciclo d e vida . . .

1 Este estado de bean de sesi6n son 10s datos de comprador para un determinado comprador: nombre, ()) direcci6n, etc. El estado es cargado desde la base de datos por un metodo ( 1 o a d S t a t e ~ r o m D a t a b a s e y guardado en la base de datos por otro metodo ( s a v e S t a t e T o D a t a b a s e ( ) ). Este bean esti destinado a proporcionar una representaci6n de un comprador determinado orientada a1 objeto; se accede a 10s datos como propiedades del o b j e t o ~ uts omer. i C u i n d o son invocados nuestros mktodos para cargar y guardar el estado en la base de datos? Quizis se este imaginando c6digo de cliente atestado por llamadas a estos mitodos, rodeando la 16gica de empresa. Esto seria una desventaja de 10s beans de sesi6n en comparaci6n con beans de entidad, que tienen retrollamadas especiales que ayudan a1 contenedor a gestionar su estado automiticamente.

Beans de entidad y persistencia


U n bean de sesidn puede, sin embargo, duplicar estas retrollamadas especiales de estado gestionado por contenedor irnplernentado lainterfaz j a v a x .e j b s e s s i o n s y n c h r o n i z a t i o n , que lepermitesaber cuindo ha cornenzado una transacci6n, cuindo esti a punto de ser cornpletada y cuindo ha sido cornpletada. Esto proporciona a 10s beans de sesi6n retrollamadas opcionales que el contenedor utilizari para notificar al bean cuindo cornienza una transaccion y cuindo esa transacci6n esti a punto de finalizar. Los lirnites de transaccibn son puntos excelentes en 10s que sincronizar el estado del objeto con la base de datos.

Una transaccidn es wn grwpo de operaciones qwe deben ser procesadas como wna unica wnidad. Para ser considerado transactional, el grwpo de operaciones qwe componen esta rinica wnidad de trabajo debe mostrar ciertas caracteristicas bien definidas, a menudo referidas por el acrdnimo mnemote'cnico A C I D , las siglas de las palabras ato'mico, consistente, aislado y duradero. Para mcis infomacidn sobre transacciones y su wso en tecnologia Enterprise JavaBeans, remitase a1 Capitwlo 17.
Cuando se notifica al bean que la transaccidn ha cornenzado, este puede invocar el mitodo 1 o a d S t a t e F r o r n D a t a b a s e ( ) o alguno equivalente. Cuando el contenedor notifica a1 bean que la transaccion esti a punto de finalizar con exito, el bean de sesi6n puede guardar sus datos en la base de datos en ese rnornento, invocando s a v e s t a t eToDat a b a s e ( ) . Este es el pseudo-c6digo que necesitaremos afiadir al bean de sesion de comprador para conseguir sincronizarlo en 10s lirnites de la transacci6n:
public

//

...

class

Customer

implements

SessionBear,,

SessionSyrjt:hronization

public vaid afterBegini ) { 1oadStateFrontDatabase( ) ;

I
pubiiz void

a f t e r r o m p l e t i o r ~ ( b o o l e a rc ~ ommit)
be used to restore the state

This

zould

* t o w h a t i t was b e f ( , r e t h e t r a t ~ l i s a c t i o n b e g a n , * i f commit w e r e t o b e f a l s e ( i n d i c a t i r q a * rollback)


+/ / / Vacio

I
public vsid beforeCcmpletion I )

1
rolled back

/*
+
+

t h i s method w i l l o n l y be c a l l e d i f the trar~cactiorh ~a s n o t b e e n

*/
saveStateToDatabase0;

I I

A primera vista, parece que ahora tenernos una representaci6n perfectamente adecuada de una entidad de cornprador, utilizando solo un bean de sesi6n con estado. Recuerde, no obstante, que este bean de sesi6n representa el estado del cornpador s61o para un rinico cliente. Para cornprender la limitaci6n de utilizar estado privado conversacional para representar datos compartidos, considere el caso de dos beans de sesi6n en una transaccion que necesita acceder a datos del cornprador.
Imagine que estamos procesando un pedido. Como parte de este pedido, necesitamos cambiar la direcci6n de envio del cornprador y carnbiar tarnbien el credit0 disponible del comprador. Estas actividades son realizadas por 10s beans de sesion sin estado de "gestionar preferencias" y de "gestionar cuentas", respectivamente. Corno parte de su trabajo, arnbos beans de sesi6n con estado necesitan alterar datos

Capitulo 16
gestionados por el objeto Customer. Cada uno creari un bean de sesi6n con estado para representar a1 comprador, utilizando el metodo c r e a t e ( ) para asociar el I D del comprador con el bean. Cada uno invocari el metodo de empresa apropiado sobre su respectivo bean de sesi6n. Digamos que esos mktodos
sonsetCustomerPreferen~es(C~st~merPreferencesViewpreferences)y setAvailableCredit(doub1e availablecredit).

A medida que 10s mktodos de empresa son invocados, cada bean de Comprador (el de "gestionar preferencias" y el de "gestionar cuentas") se afiade a la transacci6n. Cuando esto sucede, se invoca af t e r B e g i n ( ) sobre cada bean y 10s datos de estado son cargados. Observe que tenemos dos copias de 10s mismos datos de estado. Cada copia solo es accesible para su cliente. Nos enfrentamos ahora a nuestro primer dilema. Los beans de sesidn "gestionar preferencias" y "gestionar cuentas" ofrecen un servicio, per0 no mantienen el estado asociado a un determinado cliente, transaccion o mitodo. Esto incluiria cualquier referencia a 10s beans de comprador que estin utilizando. ?QuC hacemos entonces con 10s beans de Comprador? Recuerde que tienen estado y que estin consumiendo recursos de servidor. Tenemos dos opciones, una de ellas ilegal y la otra, desaconsejable:

o Podriamos intentar eliminar el bean, per0 es ilegal; un bean de sesion con estado no puede ser
eliminado mientras se encuentra en medio de una transacci6n. (Aunque pudiera ser eliminado, tendriamos que invocar manualmente el metodo savestateToDatabase ( ) ,porque el bean no se encontraria alli a1 final de la transacci6n para ser invocado automiticamente. Pero ni se le ocurra invocar remove ( ) sobre el bean; la especificaci6n lo prohibe y el contenedor generaria una excepci6n.)
0

Alternativamente, podriamos dejar que 10s beans caducaran automiticamente y fueran eliminados por el servidor de la aplicacion. Pero resulta confuso y podria provocar problemas de rendimiento. El contenedor EJB gestionard nuestro estado y referencias a 10s EJB, aunque nunca se vuelva a acceder a ellos.

Compare este caso con el de beans de entidad. Se trata de objetos compartidos y la instanciaci6n y destrucci6n de 10s EJB es gestionada directamente por el contenedor. En el ejemplo que estamos considerando, 10s beans de sesi6n "gestionar preferencias" y "gestionar cuentas" pueden utilizar sus referencias de bean de entidad y olvidarse de ellas. Puesto que 10s beans de entidad no pertenecen a ningun cliente, el cliente no es responsable de eliminarlos del contenedor. Recuerde que 10s metodos de ciclo de vida para la creaci6n y eliminaci6n de beans de sesi6n se refieren a1 EJB en el contenedor, per0 10s metodos de ciclo de vida para creaci6n y eliminaci6n de beans de entidad se refieren a1 mecanismo subyacente de almacenamiento, como a una base de datos. Este dilema no es el unico a1 que nos enfrentaremos en el uso de este bean de sesi6n con estado para representar un objeto Comprador. Hemos visto en el ejemplo anterior que puede haber multiples copias de 10s mismo datos, porque un bean de sesi6n representa datos privados, conversacionales y no datos compartidos, transaccionales. Cuando hay multiples copias, esas copias pueden estar desincronizadas. En una o en ambas copias, 10s datos pueden estar desfasados. En nuestro ejemplo, hay dos copias del bean de sesi6n con estado que participa en la transacci6n. Una pertenece a1 bean "gestionar preferencias" y tiene una nueva direccidn de envio; y otra pertenece a1 bean "gestionar cuentas" y tiene un nuevo valor de crkdito disponible. Cuando la transaction este a punto de realizarse, el contenedor invocari bef o r e c o m p l e t i o n ( ) secuencialmente sobre 10s dos beans de comprador (en un orden indefinido). El primer bean actualizari la informacion de la base de datos cuando se invoque el metodo b e f o r e c o m p l e t i o n ( ) . Cuando se invoque el metodo bef o r e c o m p l e t i o n ( ) del segundo bean, escribird sobre la informacion de la base de datos situada alli por el primer bean. Los datos de la base de datos quedarin en un estado inconsistente. Compare este caso con el de beans de entidad. Como se trata de objetos compartidos, 10s cambios de un cliente en una transaccih (el bean "gestionar preferencias") se reflejarin en un acceso por un cliente

Beans de entidad y persistencia


diferente (el bean "gestionar cuentas"). En lo que se refiere a 10s clientes, s61o hay un bean, a1 que ambos estin accediendo. Los datos del bean, a1 ser datos compartidos, se mantendrin en estado consistente. (Una opci6n es considerar que el bean de entidad es un proxy para 10s datos de la base de datos.)

Utilizar un bean de sesion sin estado


Entonces no podemos utilizar un bean de sesi6n con estado como mecanismo para representar un objeto entidad. Consideremos c6mo podriamos intentar representar un objeto entidad utilizando un bean de sesion sin estado. Nuestra carencia de estado tiene dos consecuencias:
0

El bean de sesi6n sin estado referenciado por el cliente no puede ser asociado a una identidad (con una clave primaria de una fila de la base de datos), porque no podria recordar esa identidad de llamada de metodo a llamada de mitodo. (Esta raz6n es la misma que explica por q u i un bean de sesi6n sin estado nunca tendri un metodo c r e a t e ( ) con parametros.) Asi que tendremos que pasar la identidad que representa la sesi6n actual para cada invocaci6n de mitodo. El bean de sesi6n sin estado n o puede almacenar en cache ninguna informaci6n asociada a la entidad. Esto significa que cualquier informaci6n necesaria para procesar un mitodo de empresa debe ser leida durante ese mttodo y cualquier actualizaci6n de la informacidn debe ser escrita inmediatamente en el almacin de datos. Por este motivo, cada mitodo que acceda a estado va a tener a1 principio c6digo de lectura de datos y cada metodo que modifica estado va a tener c6digo de escritura de datos en su cierre.

Nuestro bean sin estado de p r u e b a ~ u s t o m e podria r ser asi:


public class C ~ ~ s t o m e implemerltc r SecsionBean [ public vnid setCustomerNamz (Strir~rjc~_csti~rnerID, Strir~g customerName) { Connection con = null; try i c o n = getConnection ( ) ; Preparedstatement statement = corl.preparestatement ( "llPljATE Custnmer SET Name=? WHERE id=?" ) ; s t a t e m e n t . s e t S t r i n g ( 1 , customtrNarne); statemer~t.setString(Z, cust~rnerID); ir~t updated = statement. executeUpdate ( ) ; i f (updated ! = 1 ) { throw new EJBEzception ("Customer not found. " ) ;
J

catch ( S Q L E x c e p t i ~ r s ~q l e ) [ throw new EJBEzception(sq1e); 1 finally { try i if (cor~ ! = r~u11) { con. close ( ) ;
)

catch

( E ~ c e p t i o ne ) { 1

I
I
public String getCustomerName(Strir~g cust,>n~erII?l{ Conr~ecticuri con = null; try con = getcannection(); Preparedstatement statement = c~>n.prepareStatement ("SELErT Name FROM Customer WHERE id=?"); etatenlent .setstring ( 1 , c u s t o m e r I D ) ; Resultset resultset = statemer~t.executeQuery(); i f ( ! resultset .next ( ) ) {

Capitulo 16
throw new EJBExceptior~ ("Customer n<,t f o u n d . " ) ;

1
)

r e t u r n resultSet.yetStririy(1); c a t c h (SQLException s q l e ) { t h r o w new E J B E ~ ~ c e p t i o (s nq l e ) ; finally { try i i f (con ! = . n u l l ) { con.close( );

I
)

catch

(Exception e )

Este codigo tiene uno de 10s defectos presentados en la version con estado de nuestro bean de sesi6n de comprador. Primero, el cliente no necesita preocuparse por la eliminaci6n del bean de sesi6n. Puesto que cada operation en un bean de sesi6n sin estado es atornica (10s cambios en el estado no serin visibles en llamadas posteriores), invocar remove ( ) sobre uno de ellos durante una transaccion no es un error. Incluso si no invoca remove ( ) ,probablemente no haya consecuencias negativas porque no hay recursos de servidor asociados a la identidad del bean de esta sesi6n. En segundo lugar, no hay caches privadas de estado que puedan quedar desincronizadas e inconsistentes. Todo el estado se mantiene en la base de datos (o en otro almacen de datos) y cualquier base de datos que utilice para datos de empresa seri multi-usuario y transaccional. Esto significa que la base de datos gestionari accesos concurrentes y asegurari que sus datos siguen siendo inconsistentes. Esto no significa que este enfoque convierta en obsoletos 10s beans de entidad. Lo primer0 que debemos observar en este c6digo es que seri costoso de escribir, a menos que se utilice a l g h tip0 de herramienta para generar clases de acceso a datosxntegrar SQL directamente en Java es una tarea tediosa y proclive a errores, que dificulta el mantenimiento futuro. El segundo aspect0 en que debemos reparar es que el bean de sesion sin estado de comprador no proporciona una vista de sus datos orientada a1 objeto. En su lugar, ~ r o ~ o r c i o una n a biblioteca de funciones de las utilizadas en ~ r o" gramacih C. N o hay nada de malo en este enfoque desde el punto de vista de la correction de c6digo. La tarea que nosotros hemos establecido, sin embargo, ha sido proporcionar una representation de un comprador orientada a1 objeto: funcionalidad mris datos. El bean de sesion sin estado de "comprador" solo tiene funcionalidad; no tiene datos, ni tiene identidad.
A A

Implementar su modelo de empresa sin beans de entidad podria ser una elecci6n vilida para cierta clase de problemas. Por ejemplo, quizis necesite acceso muy especifico a la base de datos cubierta por el modelo C M P definido en la especificacion EJB 2.0, como la necesidad de utilizar SQL propietario a su base de datos. Sin embargo, tendri que limitarse a1 enfoque de "biblioteca de funciones" de acceso direct0 a base de datos, en lugar del enfoque mis orientado a1 objeto permitido por beans de entidad. Si solo tiene pensado leer 10s datos (no escribir), entonces no hay ningun motivo para no utilizar beans de sesion sin estado; de hecho, resulta mis eficiente que utilizar beans de entidad cuando no tenemos que preocuparnos de escribir en la base de datos.

Ventajas de 10s beans de entidad


Los beans de entidad ofrecen ventajas que van mis alli de permitirle simplemente representar estado, compartido, transaccional en su modelo de objeto (10s datos a 10s que accedemos son recuperados en una transaccion). A1 mantener la filosofia general de la tecnologia Enterprise JavaBeans, el contenedor EJB

Beans de entidad y persistencia


proporcionari a1 desarrollador de EJB una serie de servicios de persistencia de nivel de sisterna con el objetivo de concentrarse en la prograrnacidn de bgica de ernpresa. Los cuatro servicios principales son:
0

Retrollamadas de contenedor que le informan sobre el progreso de la transaccidn actual Estas retrollamadas desernpefian el rnisrno papel que nuestros rnktodos caseros a f t e r B e g i n ( ) , 1 o a d S t a t e F r o m D a t a b a s e ( ) , b e f o r e c o m p l e t i o n ( ) y s a v e S t a t e T o D a t a b a s e ( ) cuando hernos intentado construir un bean de entidad a partir de un bean de sesidn con estado. Compatibilidad con accesos concurrentes El contenedor tiene diversas estrategias que puede ernplear con este objetivo. Una consiste sirnplernente en diferir el control concurrente a la base de datos, corno hernos hecho con el bean de sesidn sin estado de cornprador en el cddigo anterior. O t r a estrategia, apropiada en ciertas circunstancias, consiste en sincronizar el acceso a un Gnico bean de entidad con una deterrninada identidad. Los contenedores EJB tarnbikn pueden utilizar una cornbinacidn de estos rnktodos. Mantenimiento de u n cache entre transacciones Dependiendo de la aplicacidn de 10s patrones de acceso a la base de datos, esto puede rnejorar significativarnente el rendimiento. Proporcionar todo el codigo de gesti6n de persistencia Cada contenedor sornetido a EJB 2.0 se encargari de guardar 10s beans de entidad en su nornbre, si asi lo elige y esto puede fornentar enormernente la productividad. Muchos desarrolladores le dirin que &a es la principal ventaja de 10s beans de entidad, incluso de la tecnologia Enterprise JavaBeans en general. La persistencia gestionada por contenedores n o s61o puede liberar a1 desarrollador de escribir cddigo de acceso a datos (norrnalrnente JDBC y SQL), sino que tarnbikn proporciona optirnizaciones corno actualizaciones cuidadosarnente ajustadas s61o de datos relevantes.

Persistencia gestionada por contenedor versus persistencia gestionada por bean


El contenedor EJB puede gestionar el proceso de guardar y restaurar el estado de sus beans de entidad, lo que se conoce corno persistencia gestionada por contenedor o CMP. Alternativarnente, 10s desarrolladores de bean pueden tornar el control de la persistencia del bean; esto se conoce corno persistencia gestionada por bean o BMP. Una de las decisiones de irnplernentacidn rnis irnportantes en cualquier proyecto que utilice tecnologia Enterprise JavaBeans e s t i relacionada con la forrna de gestidn de persistencia que utilizarin 10s beans de. entidad. N o hay duda de que la persistencia es uno de esos servicios de nivel de sistema que no es el dorninio apropiado de programadores de ldgica de ernpresa. La rnanifestacidn rnis comun de cddigo de persistencia es SQL. Escribir cddigo S Q L que traslada el estado de un objeto Java en arnbas direcciones desde una base de datos es un proceso tedioso, que conlleva tiernpo y proclive a errores, especialrnente si el rnodelo de datos rnuestra cualquier cornplejidad. El sisterna Enterprise JavaBeans ha sido escrito en su rnzyor parte para trasladar estos ternas de nivel de sisterna a1 contenedor EJB. Para muchos proyectos, tendri sentido aprovechar la capacidad del contenedor para gestionar la persistencia de sus beans, ya que kste deja la tarea de la sincronizacidn a1 contenedor. Sin embargo, la persistencia gestionada por bean es una eleccidn irnportante en algunas circunstancias. El problema fundamental es que, aunque cada contenedor sornetido a EJB 2.0 debe se compatible con persistencia gestionada por contenedor, la especificacidn n o indica cdmo debe ser proporcionada dicha cornpatibilidad. D e hecho, un contenedor no necesita necesariarnente ser compatible con CMP para asociar el estado de su bean de

Capitulo 16
entidad a columnas de la base de datos. Podria utilizar codification Java para escribir el bean completo en una columna y todavia cumplir 10s requisitos. Esto rara vez seria adecuado para un proyecto y podria necesitar el uso de persistencia gestionada por bean si su contenedor EJB utilizara codificaci6n. Por otro lado, este caso extremo no existe en la vida real. Cada sewidor de aplicaci6n compatible con EJB que conozco, incluidos 10s de c6digo abierto, tiene algun apoyo para asociar objetos a 10s campos en una base de datos relacional. El truco esti en determinar si su contenedor EJB tiene el nivel de compatibilidad requerido para persistencia gestionada por contenedor. Si lo tiene, aprovkchelo para liberar a 10s prograrnadores de 16gica de ernpresa de escribir lbgica de persistencia. El estirnulo de la productividad es potencialmente muy arnplio y, dependiendo del contenedor EJB, el aurnento del rendirniento de la aplicacion tambien puede ser significativo. 'EJB 2.0 introduce un rnodelo C M P que supone una rnejora irnportante respecto de 1.1. Un contenedor que dP ajuste a EJB 2.0 se encargari autorniticarnente de tareas complejas corno el rnantenirniento de relaciones entre sus beans de entidad o la generaci6n de cornplejas solicitudes SQL que le permitan procesar esas relaciones. El rnodelo C M P de EJB 2.0 tambien aporta otras ventajas, rnis discretas, que es necesario que conozca. Por ejernplo, utilizando persistencia gestionada por bean, una consulta de buscador que tome varios beans sera traducida norrnalrnente en dos llarnadas distintas a la base de datos: una para consultar las claves prirnarias y otra para tornar 10s beans. Si utiliza CMP, el contenedor puede emitir s61o una solicitud a la base de datos. Esto no es viable con BMP debido a1 mod0 en que lo define la especificaci6n. Este es realrnente un punto sutil per0 recuerde que C M P 2.0 tiene rnuchas ventajas sirnilares ocultas, asi que debe tener excelentes justificaciones si decide seguir el carnino BMP. Si tiene dudas, elija C M P y considere carnbiar a BMP cuando este seguro de que esti viendo problernas de rendirniento que podria resolver escribiendo usted rnismo el c6digo. Si su alrnacen de datos de destino es un sisterna ERP (Enterprise Resource Planning) o alguna otra aplicaci6n existente, probablernente necesitari utilizar persistencia gestionada por bean. En lugar de escribir c6digo SQL, probablernente utilizari protocolos especificos del vendedor, que no serin compatibles con un contenedor EJB genirico. Si su alrnackn de datos de destino es una base de datos relacional y su contenedor EJB no es compatible con C M P para su proyecto, tiene cuatro opciones:
0

Encontrar otro contenedor EJB Esta opci6n no es posible para todos; quizis esti escribiendo cornponentes para reventa y no quiere lirnitar su rnercado o quizis es un desarrollador de aplicaciones lirnitado por la decisi6n tornada por otro. Sin embargo, hay sewidores de aplicaci6n con sofisticadas funciones de asociaci6n objeto/relacional en el rnercado. Debido a enorrnes ventajas de productividad en el uso de persistencia gestionada por contenedor, las capacidades de un sewidor de aplicaci6n en este aspecto deben ser consideradas a la hora de tornar una decisi6n de tecnologia. A rnedida que mls contenedores EJB irnplernenten la especificaci6n EJB 2.0, este aspecto iri perdiendo irnportancia. Utilizar una herramienta de asociacidn objeto/relacional de terceros Puede utilizar una herrarnienta objeto/relacional de terceros con beans de entidad y persistencia gestionada por bean, o utilizando beans de sesi6n exclusivarnente (corno TopLink o CocoBase). Esta es una buena opci6n, aunque tiene dos principales desventajas: el coste (muchas de estas herrarnientas de asociaci6n objeto/relacional son caras, aunque hay a1 rnenos un proyecto irnportante de c6digo abierto para desarrollar una herrarnienta de este tipo) y, en segundo lugar, ha ligado su aplicaci6n a un sisterna tercero de propiedad. Algunos contenedores EJB son capaces de integrar herrarnientas de asociaci6n objeto/relacional de tercero de rnodo que la su funcionalidad sea accesible para beans utilizando persistencia gestionada por contenedor. Esto hace que 10s beans de entidad sean rnis sencillos de desarrollar, evita que el desarrollador se vincule al product0 y perrnite a la herrarnienta de terceros aprovechar algunas optirnizaciones adicionales.

Beans de entidad y persistencia


0

Cambiar su diseiio Puede cambiar su disefio para reflejar las limitaciones de su herramienta elegida y utilizar persistencia gestionada por contenedor. (Dependiendo de las limitaciones y de sus necesidades, quizis esto no sea posible.) Por ejemplo, su contenedor EJB quizis no sea compatible para asociar objetos dependientes en sus propias tablas con una relacion de clave secundaria a la tabla principal. Si su contenedor pudiera modelar relaciones entre beans de entidad, podria elevar esos objetos dependientes a beans de entidad de primera clase para preservar un disefio normalizado de base de datos. Este enfoque tiene dos desventajas: el rendimiento (como en el ejemplo de objeto dependiente, su nuevo disefio puede tener como resultado una implementaci6n de modelo de objeto rnis pesado) y su disefio modificado puede ser mis dificil de implementar, mantener y comprender. Escribir su propio codigo de acceso a datos Es un imuortante comuromiso decidir si sus desarrolladores se resoonsabilizan de escribir el c6digo de persistencia que requiere su aplicaci6n. Si asi lo decide, debe encapsular el codigo de uersistencia en comuonentes de avuda de acceso a datos de sus beans de entidad. Si encuentra que una parte significativa de sus esfuerzos de desarrollo es invertida en escribir instrucciones SQL dentro de mktodos de retrollamadas en beans de entidad, detCngase y reconsidCrelo. La expectativa de 10s escritores de la especificaci6n EJB era que la mayoria de EJB que utilizaban persistencia gestionada por bean serian creados utilizando una herramienta. La secci6n 12.1.1 del Borrador 2 Final Propuesto de la especificaci6n EJB afirma:

"Esperamos que la mayor parte de 10s beans de empresa con persistencia gestionada por bean Sean creados por herramientas de desarrollo de aplicaciones que encapsulara'n acceso a datos en componentes. Estos componentes de acceso a datos probablemente no sera'n iguales para todas las herramientas. Adema's, si las llamadas de acceso a datos son encapsuladas en componentes de acceso a datos, 10s componentes de acceso a datos quiza's requieran intefaces de implementacidn para permitir la adaptacidn de acceso a datos a diferentes esquemas o incluso a diferentes tipos de bases de datos. Esta especijkacidn EJB no define la arquitectura para objetos de acceso a datos, las estrategias para adaptar e implementar componentes de acceso a datos o asegurar la portabilidad de estos componentes para persistencia gestionada por bean ..."
A medida que las capacidades de 10s contenedores EJB siguen mejorando frente a la feroz competencia que se ha desarrollado entre implementadores de este API y dados 10s cambios realizados en el modelo de persistencia de la especificacion EJB 2.0, las sofisticadas capacidades de asociaci6n objeto/relacional estin obligadas a convertirse en omnipresentes (10s vendedores de servidor de aplicaci6n afiadirin estas capacidades a sus productos y estas interfaces se desarrollarin para permitir que herramientas objeto/ relational de terceros se integren en contenedores EJB). A medida que pase el tiempo, no tendri mis sentido que 10s programadores de logica de empresa disefien c6digo de asociacidn objeto/relacional que escriban bases de datos relacionales. Todavia no ha ]legado el momento per0 es necesario realizar una detenida evaluacidn de los requisitos de la aplicaci6n y de las capacidades de las herramientas antes de tomar la decision de escribir beans de entidad que gestionen su propia persistencia.

Nuevas funciones para CMP introducidas en EJB 2.0


Si ya esti familiarizado con EJB 1.1 y esti ascendiendo a EJB 2.0, esta secci6n le resultari interesante. La especificaci6n EJB 2.0 introduce algunas mejoras radicales, especialmente para persistencia gestionada por contenedor. Las principales incorporaciones son:
0 0

Accedentesabstractos Interfaces locales

Capitulo 16
0

Relaciones

O El Lenguaje de Consulta EJB


Estas cuatro caracteristicas son posibles gracias a la introducci6n de un nuevo actor en el rnodelo EJB. Inicialrnente llarnado "Gestor de persistencia" en 10s prirneros borradores de la especificaci6n EJB 2.0, este actor perdi6 eventualrnente su identidad y se convirti6 en parte del contenedor. Por lo tanto, todos 10s contenedores EJB 2.0 tienen que irnplernentar sus semicios. Para el contenedor, esto significa que las herrarnientas que utiliza para procesar Enterprise JavaBeans (Ilarnadas e j bc en BEA WebLogic, por ejemplo) generarbn mbs c6digo para proporcionar todos estos semicios. En concreto, como veri en las siguientes tres secciones, la implementaci6n de las anteriores caracteristicas se realiza a travCs de mktodos abstractos que el contenedor implementarb en el c6digo generado.

Accesores abstractos
U n bean de entidad C M P es esencialmente definido por sus campos CMP: 10s campos Java que estin asociados a tablas en la base de datos. La especificaci6n EJB 1.1 era muy poco concreta en cuanto a la forma de representaci6n de estos campos en la clase bean. La especificaci6n EJB 1.1 irnpone que estos campos C M P sean definidos por accesores abstractos en lugar de campos Java. Por ejemplo, un campo C M P llamado nickName seria declarado de la siguiente forma:
public public abstract String getNickName ( ) ; abstract void setNickName(String nickname);

Observe que en nuestra base de datos, puede que n o tengarnos una colurnna llamada nickName; n o pasa nada ya que s61o tenernos que especificar c6mo asociar campos C M P en el descriptor de implementaci6n. Lo veremos rnis adelante. Esto parece un carnbio inofensivo per0 tiene rnuchas consecuencias sobre el rnodelo CMP en general desde el punto de vista del rendirniento. El punto rnis irnportante es que el contenedor tiene ahora control total sobre el acceso de carnpos. Corno generarb c6digo para cada accesor, es capaz de tomar todo tip0 de decisiones y optirnizaciones sobre c6rno recuperar 10s datos. La especificaci6n EJB 2.0 no establece ninguna irnplernentaci6n concreta per0 hay algunas ventajas que proporcionan habitualrnente 10s contenedores EJB 2.0 gracias a este nuevo disefio: Carga lenta de beans Ahora que el contenedor sabe exactarnente quC carnpos son accesibles y cubndo se puede acceder a ellos y no tiene que cargar el estado cornpleto del bean en e j bLoad ( ) . Puede decidir n o hacer nada cuando el bean es tomado inicialrnente y s61o decidir ernpezar a cargar el estado en la prirnera llamada de uno de 10s rnCtodos de obtenci6n. Esto puede ser especialrnente irnportante cuando se inicie su aplicaci6n y cientos de beans sean tornados en memoria en el arranque. TarnbiCn es una funci6n rnuy irnportante cuando se vincula a1 "grupo de carga" (vkase rnis adelante).
0 Actualizaciones ajustadas

Una irnportante irnperfecci6n del rnodelo EJB 1.1 C M P y su n o definici6n del acceso a carnpos C M P consiste en que el contenedor n o podia indicar quC carnpos habian sido rnodificados durante una transacci6n. Consecuentemente, 10s vendedores de contenedores ernpezaron a proporcionar extensiones de propiedad a1 rnodelo con el objetivo de obtener esta inforrnaci6n. La rnis cornfin es la introducci6n de un metodo boolean isModif ied ( ) que devolvia el valor t r u e si el bean habia rnodificado uno de sus carnpos durante la transacci6n. Este enfoque tiene dos serios inconvenientes:

O El proveedor de bean debe implernentarlo, lo que conlleva rnantener un registro de 10s carnpos que han sido rnodificados

Beans de entidad y persistencia


o Lo Gnico que sabe el contenedor es que el bean ha sido modificado, per0 no sabe
especificamente quk campos han sido modificados Los accesores abstractos de EJB 2.0 hacen frente a todas estas deficiencias. El proveedor de bean ya no tiene que registrar quk campos han sido modificados (despuks de todo, ksta es persistencia gestionada por contenedor, asi que debemos esperar que el contenedor haga todo este tfabajo por nosotros) pero, principalmente, sabe exactamente quk campos han sido modificados. Consecuentemente, cuando se realiza la transaccion, es capaz de emitir una "actualizaci6n ajustada" a la base de datos: una solicitud SQL que actualizari solo columnas correspondientes a campos modificados durante la transaccion.

Carga de grupos Otra interesante caracteristica que puede ofrecer un contenedor en permitirle definir grupos de campos. Por ejemplo, supongamos que su bean de entidad contiene campos sencillos como numero enteros, cadenas, etc. per0 tambikn contiene un gran objeto binario (una imagen, por ejemplo). Si codifica esto inocentemente y ejecuta una consulta que toma su bean, el estado completo va a viajar por la red, incluido la imagen. Esto es un gasto de ancho de banda si el cliente que emiti6 la solicitud no esti interesado en la imagen. Para atajar este problema, WebLogic introduce el concepto de "grupos de campo". Cuando se accede a una campo, el resto de campos que pertenecen a1 mismo grupo tambikn serin tornados por el contenedor, per0 no 10s otros. En el ejemplo de la imagen de grandes dimensiones, pondria la imagen en un grupo y el resto de campos en un grupo diferente. Asi, siempre que acceda a un campo que no sea la imagen, el gran objeto binario nunca sera tomado.

~ s t o son s detalles especificos de implementation per0 puede confiar en que muchos contenedores EJB 2.0 10s proporcionen ya que se enfrentan claramente a problemas del mundo real.

Interfaces locales
La especificacion EJB 2.0 introduce un nuevo concepto: interfaces locales. En EJB 1.1, las unicas interfaces que necesitaba en un bean eran remotas: inicio remoto y objeto remoto. U n problems relacionado con las interfaces remotas es que, puesto que utilizan RMI como protocolo de acceso remoto, tienen que obrar de acuerdo con las reglas de transporte RMI: 10s parametros deben ser pasados por valor, 10s mktodos deben generar excepciones RemoteException en su firma, etc. Examinemos una de estas restricciones: pasar por valor. Esta sencilla restriccion tiene un profundo impact0 de rendimiento en sus beans: cada llamada de mktodo sufre un gran sobregasto puesto que 10s parimetros deben ser clonados en ambas direcciones. Aunque esta restriccion n o tiene sentido cuando el que llama y a1 que llaman estin efectivamente en equipos diferentes, tpor quk debemos pagar este precio cuando ambos estin en el mismo equipo virtual? Por ejemplo, un tipico caso es el de un bean que invoca un mktodo en otro bean (un bean de sesi6n sin estado que invoca un bean de entidad en el mismo contenedor). En este caso concreto, las restricciones RMI son innecesarias y pueden hacer que las llamadas resulten innecesariamente caras. Por lo tanto, el grupo experto EJB introdujo interfaces locales. U n bean puede ahora exponer dos tipos de interfaces: una interfaz remota y una interfaz local (puede exponer ambas o solo una de ellas). Esta dualidad ha sido ampliada a objetos EJB, que pueden ahora ser remotos o locales. Una interfaz inicial local devolveri objetos EJB locales. Las llamadas de mktodo sobre interfaces locales obedecen a la semintica estindar de llamadas Java: no se realizan copias de parimetros, garantizando el miximo rendimiento. La situacion anterior puede ser rescrita ahora del siguiente modo: el bean de sesi6n sin estado expone una interfaz remota, que es la interfaz que utilizarin 10s clientes remotos para comunicar. El mismo bean de sesion sin estado buscari la interfaz inicial local del bean de entidad. Desde esta interfaz, podri crear o buscar beans de entidad locales y, sobre estos beans, podri invocar mktodos con semintica de llamada estindar "pasar por referencia".

Capitulo 16 Relaciones
U n programa Java manipula habitualmente grificos de objetos: objetos que contienen objetos que contienen mis objetos. Obviamente, cuando utilizamos beans de entidad, queremos que el almacen persistente refleje estas cornplejas relaciones, per0 la tarea no es muy ficil debido al hecho de que las bases de datos relacionales almacenan tablas (filas y colurnnas). Por lo tanto, se necesita una cierta cantidad de trabajo para asociar un grifico de objetos Java a tablas. EJB 1.1 no especificaba nada en ese irea, por lo que 10s proveedores de beans a rnenudo recurrian a persistencia gestionada por bean para almacenar sus objetos Java. EJB 2.0 introduce el concept0 de relaciones gestionadas por contenedor, que se enfrenta a este problerna. Brevemente, lo Gnico que tienen que hacer 10s proveedores de beans es definir la relacion entre sus beans en sus descriptores de irnplernentacion y el contenedor EJB 2.0 generari todo el cddigo Java y las instrucciones necesarias para persistir y procesar las relaciones. Las relaciones pueden ser unidireccionales (un pedido con articulos de linea pero articulos de linea sin un pedido) o bidireccionales (puede localizar el pedido desde el articulo de linea, asi corno localizar el articulo de linea desde el pedido) y pueden ser de tres tipos:
0 Una-a-una: persona y nGrnero de la seguridad social

o Una-a-varias: persona y pedido de compra


0 Varias-a varias: persona y suscripcion a revista

El contenedor genera codigo que se responsabiliza de las siguientes tareas:


0 Mantener integridad referencial (si una persona cambia su nGmero de la seguridad social, el bean del n6rnero de la seguridad debe ser tarnbih destruido) 0 Manejar la adicion y elimination de beans desde una relacion de varias, y persistir el nuevo estado 0 Capacitar la navegacion a traves de relaciones generando instrucciones SQL que seleccionen 10s carnpos correctos

Lenguaje de consulta EJB


Una de las ventajas de la persistencia gestionada por contenedor es que le abstrae del alrnackn persistente subyacente: no necesita saber corn0 se almacenan sus beans o que tip0 de base de datos se esti utilizando. Una consecuencia de este requisito es que necesita un lenguaje independiente de la base de datos para expresar las consultas. Por ejernplo, querri tener una consulta que realice la siguiente bGsqueda: "Encontrar todos 10s ernpleados cuyo apellido sea Beust". Antes de EJB 2.0, no existia un lenguaje estindar de este tipo, por lo que todos 10s vendedores de contenedores EJB disefiaban el suyo propio. EJB 2.0 introduce EJB QL, EJB Query Language. EJB Q L es un lenguaje cuya sintaxis se parece a SQL (aunque es diferentes en distintos aspectos). Igual que las relaciones, las instrucciones Q L EJB son especificadas en 10s descriptores de implementation y el contenedor generari la instrucci6n SQL correspondiente (que no tiene que por qui ser SQL) para llevar a cab0 su consulta. Verernos algunos ejernplos de Q L EJB en la irnplernentaci6n de nuestro ejernplo mis adelante en este capitulo pero, por el rnornento, examinemos algunas de las caracteristicas de Q L EJB. El reto que EJB Q L esti intentando resolver es asociar dos rnundos diferentes: objetos Java y filas de bases de datos. Hoy por hoy, las bases de datos relacionales (RDBMS) todavia prevalecen, per0 esto podria carnbiar en el futuro a rnedida que las bases de datos orientadas a objetos (OODBMS) se hagan cada vez rnis populares. EJB Q L esti intentando abstraerle de este posible carnbio de paradigrna de rnodo que con cualquier lenguaje de consulta que se utilice para tornar datos de la base de datos, su EJB siga trabajando.

Beans de entidad y persistencia


La sintaxis de EJB Q L es muy similar a la de SQL per0 no se equivoque: las nociones subyacentes son muy diferentes y necesita comprender c6mo interactuan 10s objetos Java y las instancias de EJB si quiere aprovechar todas las ventajas que ofrece EJB QL. O t r o aspect0 sobre EJB QL es que, una vez que ha entendido c6mo funciona, puede utilizarlo con 10s siguientes fines:
0 0

Implementar buscadores Implementar metodos de selecci6n (10s metodos e j b s e l e c t ( ) son nuevos en EJB 2.0, son bisicamente "buscadores privados": cuando desee utilizar EJB Q L en su propio beneficio per0 no quiera exponer el mitodo al cliente remoto, como seria el caso si utilizar un buscador)

O Navegar entre relaciones


Una consulta EJB Q L es una cadena que consiste en las tres siguientes cliusulas (no todas ellas son 0b1i~atoria.s dependiendo de la aplicacidn de la cliusula):

O Una cliusula SELECT, que determina el tipo de objetos o valores que serin seleccionados
0

Una cliusula FROM, que proporciona declaraciones que designan el dominio a1 que se aplican las expresiones especificadas en las cliusulas s ELECT y WHERE

O Una c~iusula opcional WHERE que puede ser utilizada para restringir 10s resultados devueltos por la consulta
Veamos una simple consulta e intentemos comprenderla:
SELECT DISTINCT OBJECT ( o1 FROM Order A S n , IN(n.lineItems) AS 11 WHERE 1i.shipped = FALSE

Examinemos cada linea sucesivamente.


La claurula SELECT

Dependiendo del tipo de metodo a1 que se aplique su consulta, la cliusula SELECT puede tomar diferentes valores:
0

A 10s buscadores ( e j b F i n d e r ~ y X X X ( ) ) s61o se les permite devolver EJB del mismo tipo que 10s creados por su interfaz inicial, por lo que el tip0 de la cliusula SELECT debe coincidir con el nombre de esquema abstracto del EJB.

O Los metodos de selecci6n ( e j bSelectXXX ( ) ) son diferentes: pueden devolver esquemas abstractos EJB arbitrarios, asi que tiene libertad para SELECCIONAR sobre cualquiera de 10s nombres de esquema abstracto definidos en el actual descriptor de implementacibn.
Ambos metodos pueden ser definidos para interfaces locales o remotas, por lo que el contenedor garantiza que el tipo de objetos EJB devueltos por la consulta coincidirin con el de inicio (EJBObj e c t si esti definido en una interfaz inicial bisica, E J B L o c a l O b j e c t si no lo esti). La palabra clave opcional DISTINCT le permite eliminar valores duplicados que podrian ser devueltos por la consulta. Esto s610 podria suceder, por ejemplo, si la C ~ ~ U ~ U ~ ~ W es H ejecutada ERE sobre algo distinto de la clave primaria o si conlleva unir varias tablas.
La clausula FROM

Hay dos partes en la cliusula FROM en esta consulta. La primera declara una variable de tipo O r d e r . ~ s t e no es el nombre del EJB. N o se le permite utilizar nombres EJB (como en < e j b-name> en e j b j a r . xml) en una consulta EJB QL, tiene que especificar una etiqueta<abstract-schema-name> en

Capitulo 16
su descriptor de implementaci6n y utilizar ese n o m b ~ e en la consulta. Sin embargo, nada le impide reutilizar el mismo nombre que el nombre del EJB. Esta es la correspondiente secci6n e j b - ja r .xml que se aplicaria a la consulta anterior:
<!-

<!-

fragment of ejb-jar.xm1 > <entity> <ej b-narne>OrderEJB</ej b-name> some elements skipped -> <abstract-schema-name>Order</abstract-schema-name>

Siempre que escriba una consulta EJB Q L que implique un determinado EJB, ese EJB necesita tener un c a b s t r a c t - s c h e m a - n a m e > definido en sudescriptor de implementaci6n. La segunda parte de esta cliusula FROM define una variable " l i " que iterari todos 10s valores del campo C M P l i n e 1t e m s de o.La palabra clave IN debe ser utilizada si el campo C M P que desea utilizar es una colecci6n y no un objeto de valor Gnico. Observe que un nGmero ilimitado de instrucciones puede ser organizado de este modo: si quiere que la consulta siga referenciando 10s campos C M P en 1i,puede aiiadirlos, separados por una coma. Recuerde que el nombre del esquema abstract0 de li es l i n e I t e m s (representado por el LineItem EJB), asi solo 10s campos C M P de ese EJB serin de uso legal en l i (como se ilustra en la cliusula WHERE). O t r o uso para tener mGltiples declaraciones en la cliusula FROM es alli donde necesite hacer comparaciones que impliquen a todos 10s beans de la tabla actual. Por ejemplo, la siguiente devolveri todos 10s empleados que le queden mis dias de vacaciones que al empleado Dave:
SELECT DISTINCT O B J E C T ( o 1 ) FROM Employee el, Employee e2 -days AND el.first-name WHERE el.vacationpdays > e2.vacatioi-1

'Dave'

La clausula WHERE
Esta cliusula contiene expresiones Booleanas que pueden ser utilizadas para limitar 10s resultados de la per0 devolveria todos 10s consulta. La consulta anterior seria perfectamente legal sin esta cliusula WHERE, pedidos, independientemente de si hubieran sido o no enviados, de ahi la condici6n extra de asegurar que el campo s h i p p e d C M P Boolean es false. La expresi6n condicional puede ser una combinaci6n de las cliusulas AND y OR. Tambien puede incluir 10s literales TRUE y FALSE. Tambien ofrece algunos potentes operadores como BETWEEN o I N ; o coincidencia de patrones con el operador LIKE, con el subrayado (-) representando cualquier caricter iinico y el signo de porcentaje (%)representado una cadena de caracteres. La igualdad se consigue con "=" y la n o igualdad con "<>". ~ s t o son s algunos ejemplos:
p.age p.age BETWEEN 1 5 and 19 ( i s equivalent to p.age >= 1 5 AND p.age <= 19)

N O T BETWEEN
IN ('red',

1 5 and 19 'blue')
(true
for

@.color

colors

'red'

and

'blue')

person. first name LIKE

' edric'

(true (true the

for
for

Cedriz and Cedriz) a n y number s t a r t i n g with


415)

person.phone number like '415%' o.lineIterns I S EMPTY


( t r u e if

Collection

is empty)

U n Gltimo comentario sobre expresiones: incluya 10s parimetros pasados el metodo buscador/seleccionar como signos de interrogacion seguidos por el orden en que aparecen en la firma. Por ejemplo, el siguiente buscador:

Beans de entidad y persistencia


abstract public Person findByNarne(String firstName, String 1astNarne);

seria implementado por la siguiente consults:


SELECT DISTINCT O B J E C T ( o ) FROM Person A S o WHERE o.firstName = ?I AND o.lastName

?2

Veamos ahora unos ejemplos para explicar cdmo funcionan 10s beans de entidad.

El laboratorio SportBean
La responsabilidad de implementar 10s servicios de persistencia de un bean de entidad recae en:
0

El desarrollador para un bean con persistencia gestionada por bean

0 El contenedor EJB para un bean con persistencia gestionada por contenedor

A medida que vayamos analizando 10s diferentes aspectos de un bean de entidad, iremos construyendo dos versiones diferentes de un dnico bean de entidad que represente un equipo de deporte: uno que utilice persistencia gestionada por bean y otro que utilice persistencia gestionada por contenedor. Podri comparar 10s pasos necesarios para implementar 10s dos tipos de beans y para ver las ventajas, desventajas y diferencias de cada uno. Habri diferencias significativas entre las implementaciones de un bean de entidad CMP y un bean de entidad BMP, debido a responsabilidades distintas. La rnayoria de estas diferencias estarin en las retrollamadas de persistencia del contenedor, 10s metodos de factoria y la clase de clave primaria, que vamos a examinar a medida que codifiquemos las dos versiones de estos beans. Nuestro bean de muestra de equipo de deportees bastante sencillo. U n equipo de deporte se identifica por un deporte (corno fdtbol o baloncesto) y un nombre de pila (corno Packers o Knicks). Ademis, tiene un nombre de propietario y un dnico "jugador franquiciaUque es el mejor jugador del equipo. Para nuestros prop6sitos, la logica de empresa no es relevante aqui; hemos incluido algunos mktodos de configuraci6n y de obtenci6n para nuestra prueba. Los mktodos de empresa pueden ser codificados igual, independientemente del tip0 de persistencia.

Claves primarias
Cada bean de entidad tiene una clave primaria que representa una identidad unica. Esta clave primaria debe ser representada por una clase de clave primaria, que define o especifica el desarrollador de bean. En otras palabras, esta clase contiene la informaci6n necesaria para encontrar esa entidad en el almacin persistente. Es utilizada internamente por el contenedor EJB y tambien por el cliente para encontrar una determinada instancia de la entidad. Esta clase debe seguir ciertas reglas. Para persistencia gestionada por bean, las reglas son muy sencillas. El formato de la clase se deja pricticamente por complete. a1 desarrollador, puesto que es el y no el contenedor EJB que la utilizari:
0 La clave primaria puede ser cualquier tip0 de valor legal en RMI-IIOP (lo que implica que se puede codificar). Bisicamente, puede utilizar cualquier objeto Java (siempre que se pueda codificar) y tambien referencias remotas. Los tipos cuyo proceso de empaquetarniento no tiene sentido (corno interfaces Java) no son tipos legales RMI-IIOP.
0

El EJB debe proporcionar irnplementaciones de 10s metodos hashcode ( ) y equals ( ) que respeten las restricciones explicadas en la documentacion de j ava .util .Hashtable.Por ejemplo, dos objetos idknticos deben tener un c6digo hash similar, per0 dos objetos que tengan el

Capitulo 16
mismo cddigo hash no necesariamente son idinticos. Para mis detalles, remitase a1 API Hashtable ( o ~ o l l e c t i o n s ) . La clave primaria debe tener un valor exclusivo dentro del grupo de todos 10s beans de un determinado tipo. Esto son solo reglas formales. Obviamente, en la prictica, la clase de clave primaria tendri campos de estado que correspondan a 10s valores de la clave primaria del bean de entidad. Por ejemplo, un bean de entidad de Comprador puede tener una clave primaria que tenga un campo c u s t o m e r I D de tipo i n t . Alternativamente, la entidad Comprador en este ejemplo puede utilizar el tip0 j a v a . l a n g .I n t e g e r , que cumple todos 10s requisitos. Hay algunas reglas extra para un bean con persistencia gestionada por contenedor. El problema fundamental es que el contenedor es responsable de gestionar la creacidn, busqueda, carga, p a r d a d o y eliminacidn de la entidad. Para hacer todas estas cosas, el contenedor necesita poder crear una clave primaria, por lo que la clase clave debe tener un constructor public0 sin argumentos. El contenedor t a m b i h necesita poder asociar el estado del bean a1 estado de la clase de clave primaria, y viceversa. Asi, hay algunas reglas diseriadas para hacer esto posible. La especificacidn proporciona dos mktodos diferentes para proporcionar clases clave para beans que utilicen CMP. U n o es un caso general, adecuado para claves primarias con cualquier niimero de campos; el otro es un caso especial, conveniente en el manejo de una clave primaria con un campo. El caso general lleva a cab0 la asociacidn utilizando una convencidn de nombres: 10s campos publicos de la clase de clave primaria corresponden a 10s campos publicos equivalentes de la clase bean. Por ejemplo, definiremos una clase de clave primaria llamada s p o r tTeamPK para nuestro bean de entidad S p o r t T e a m que tiene dos campos que forman su clave primaria: s p o r t y nickName. SportTeamPK necesitaria campos correspondientes del mismo tip0 y nombre. La clase seri asi (cambie el nombre del paquete, dependiendo de si esti introduciendo la versidn CMP o BMP):
package import s p o r t B e a n . cmp;
j aLra. i o . S e r i a l i z a b l e ;

/ / La c l a v e p r i m a r i a n e c e s i t a s e r C o d i f i c a b l e p o r q u e s e r 6 / / i n t e r c a m b i a d a e n t r e c l i e n t e s y EJB p u b l i c c l a s s SportTearnPK i m p l e m e n t s S e r i a l i z a b l e I / / L a e s p e c i f i c a c i h n irnpone q u e 10s carnpos s e a n p 6 b l i c o s / / Es urm bueria p r 6 c t i c a d e p r o g r a m a c i h n p a r a p r o p o r c i o n a r rnetodos g e t y s e t / / d e c u a l y u i e r forrna. public String sport; p u b l i c S t r i n g r~ickNarne;
public SportTearnPK
( )

p u b l i c Spc.rtTearnPK(String s p o r t , this.sport = sport; t h i s . nickNarne = nickNarne;

String

nickNarne)

I
public String getsport return sport;
( )

I
p u b l i c S t r i n g getNickNarne ( 1 r e t u r n riickNarne;
{

I
public int hashcode()

Beans de entidad y persistencia


/ / Asume q u e l a c l a v e n o p u e d e s e r n u l a
return (sport t nickName1. hashcode ( ) ;

1
p u b l i c boolean equals (Object o t h e r ) i f [ ( o t h e r == n u l l ) I l ! ( o t h e r i n s t a n c e o f return false;
J ,

SportTearnPKl 1

I
SportTearnPK o t h e r P K = (SportTeamPK) o t h e r ; r e t u r n sport.equals(otherPK.sportj & & nickName.equals(otherPK.r~ickName1;

I
1

Esta misma clase puede ser utilizada para las versiones BMP y CMP de nuestro bean de equipo de deporte, aunque podriamos tener m h flexibilidad en la versidn BMP, si quisiiramos utilizarla. Por ejemplo, podriamos nombrar a 10s campos de forma diferentes o hacerlos privados y proporcionar me'todos accedentes. En este caso, utilizaremos la misma clase para mantener la sencillez.
Observe que una clase de clave primaria debe ser inmutable: una vez que haya asociado un bean de entidad a una clave primaria, no debe reutilizar el mismo objeto de clave primaria. Esta restricci6n es la misma para contenedores Java en el paquete j ava .u t i l .c o l l e c t i o n : reutilizar la clave utilizadapara almacenar un objeto en un HashMap tendri como resultado un comportamiento indefinido. A1 hacer esto, esti realmente cambiando la identidad del objeto y el contenedor no tiene manera alguna de saberlo. D e ahi la siguiente regla: Nunca proporcione mktodos de configuraci6n (set) e n su clase de clave primaria. Si necesita u n a clave con valores diferentes, Cree u n objeto nuevo. La clase completa cualificada de la clave primaria siempre tiene que ser especifi5ada en el descriptor de implementacion para beans de entidad con persistencia gestionada por bean. Estos son algunos posibles ejemplos. El primer ejemplo es para ambas versiones (BMP y CMP, modificados a p r ~ ~ i a d a m e n tde e) nuestro bean de equipo de deporte:

El segundo caso se utilizaria si la clave identificativa para el bean de equipo de deporte solo tuviera un unico campo como clave:
< p r i m - k e y - c l a s s > j a v a . l a r ~ gS . trir~g,</prim-key-class>

En el caso de un bean de entidad con persistencia gestionada por contenedor que utiliza un tip0 sencillo como clave primaria, el desarrollador del bean especifica en el descriptor de implementaci6n el campo gestionado por contenedor del bean d,e entidad que contiene la clave primaria. El tip0 del campo debe ser el mismo que el tip0 de clave primaria. Estos son algunos posibles ejemplos:

El desarrollador EJB quizis desee utilizar una clave sintktica, como una clave de auto-incremento, como la clave primaria de su bean de entidad. Hay dos posibles estrategias. La primera consiste en generar la clave utilizando un bean de sesi6n. Este bean de sesi6n podria recuperar un bloque de claves de la base de datos y distribuir claves de forma secuencial desde este bloque para bean de entidad de solicitud. La segunda

Capitulo 16
estrategia consiste en depender de la base de datos para crear automiticamente las claves sintiticas cuando el estado del bean de entidad sea insertado. Si el bean de entidad utiliza persistencia gestionada por contenedor, las herramientas de asociacion objeto/relacional del contenedor EJB deben ser compatibles con esta funcionalidad para la base de datos de destino.

Las retrollamadas C.R.U.D.


C.R.U.D. es un acronirno que define 10s cuatro tipos de actividades que cornprenden la persistencia:
O Crear (Create)
O Leer (Read)

O Actualizar (Update) O Eliminar (Delete)


Existe un tip0 de retrollamada definido para cada una de estas actividades en beans de entidad: 10s metodos e j b C r e a t e ( ) y e j b P o s t C r e a t e ( ) ; e j b L o a d ( ) ; e j b S t o r e ( ) y e j b R e m o v e ( ) ,respectivarnente. Las firrnas de estos metodos de retrollamada son las mismas se utilice persistencia gestionada por contenedor o gestionada por bean. Sin embargo, el c6digo que escribe el programador seri rnuy diferente basindose en el tip0 de persistencia.

Crear
Cuando un cliente invoca c r e a t e ( ) para un bean de entidad, 10s datos de estado son insertados en el correspondiente alrnacen de datos (corno una base de datos relational). Estos son datos transaccionales que son accesibles desde multiples clientes. Por el contrario, cuando un cliente invoca c r e a t e ( ) para un bean de sesi6n con estado, el contenedor EJB crea un alrnach de datos privado, no transaccional en el almacenamiento temporal del servidor de la aplicacion. Es irnportante comprender esta diferencia.

Cuando invoca create() en una interfaz inicial de bean de sesih, est6 creando una instancia de ese bean de sesih, mientras que cuando invoca create ( ) en una interfaz inicial de bean de entidad, est5 realmente insertando un registro en la base de datos.
El rnetodo c r e a t e ( ) definido en la interfaz inicial del bean de entidad puede ser sobrecargado para proporcionar varias versiones y estos rnetodos c r e a t e ( ) pueden tornar diferentes parimetros, que corresponden a1 estado del bean en el rnornento de la creation. Los parirnetros deben tener inforrnaci6n suficiente para, corno minirno, inicializar la clave prirnaria y cualquier carnpo que est6 asociado a columnas especificadas corno NOT NULL en la base de datos. Todos 10s metodos c r e a t e ( ) deben devolver la interfaz remota del bean, de rnodo que cuando el programador cliente invoque c r e a t e ( ) en la interfaz inicial, tenga una referencia a ese bean sobre el que 10s mitodos de empresa pueden ser invocados. Todos 10s mktodos c r e a t e ( ) deben lanzar j ava . r m i .RemoteException, porque pueden ser rnktodos remotos. (Esto se aplica en realidad a todos 10s rnetodos de la interfaz reaota.) Tambien deben lanzar j a v a x .e j b .CreateException, que es utilizada para indicar unproblerna de nivel de aplicacion durante el intento de creation. (Tarnbien pueden lanzar excepciones definidas por el usuario.) Un ejemplo de problems de nivel de aplicacion seria el de parimetros ilegales pasados a c r e a t e ( ) .
Los d t o d o s create0 de Sports Team, interfaz inicial

Los mitodos c r e a t e ( ) para nuestro EJB de equipo de deporte son (observe que son 10s rnisrnos para la version BMP y para la versi6n CMP):

Beans de entidad y persistencia


package import import import public sportBean.crnp;
j avax. e j b.

*;

java.rrni.RemoteException; java. u t i l .Collection;


interface SportTeamHome extends EJBHome
{

SportTeam c r e a t e i s t r i r i g

sport,

S t r i r t g nickNarne)

throws

RernateExceptiort, CreateException; OwnerNarne,

SportTearn

c r e a t e i s t r i n g s p o r t , S t r i n g nickName, S t r i n g frarichisePlayer) throws RernoteException, C r e a t e E x c e p t i o n ;

String

Cada una de estas instancias sobrecargadas del mktodo c r e a t e ( ) de la interfaz inicial del bean debe tener dos mktodos coincidentes en la clase de implementaci6n del bean. Por ello, en nuestro caso, habri cuatro mktodos relacionados con la creaci6n en nuestra clase de implementaci6n. Los dos mktodos que escribimos en la clase de implementaci6n para cada c r e a t e ( ) de la interfaz inicial deben llamarse e j b c r e a t e ( ) y e j b P o s t C r e a t e ( ) y deben tener 10s mismo parimetros en el mismo orden que el mktodo inicial c r e a t e ( ) . Los mktodos deben ser declarados p u b l i c o s y no deben ser f i n a l e s o e s t a t i c o s . El tipode retorno d e e j b C r e a t e ( ) es laclase de claveprimariadel bean de entidad y el tipo de retorno de e j b P o s t C r e a t e ( ) es v o i d . (Terminaremos la definici6n de esta interfaz inicial cuando aiiadamos 10s mktodos buscador, mis tarde.) U n punto de confusi6n para muchos programadores es por quk son necesarios 10s mktodos e j b C r e a t e ( ) y e j b P o s t C r e a t e ( ) . Poregla general, el programador de bean (para persistencia gestionada por bean o persistencia gestionada por contenedor) hari todo su trabajo en e j b C r e a t e ( ) , dejandoe j b P o s t C r e a t e ( ) vacio. Laraz6n fundamental de queexistaelmktodoe j b ~ o s t ~ r e a ( t) e es que a1 programador no le esti permitido pasar t h i s como parimetro a un mktodo remoto; siempre debe utilizar en su lugar la interfaz remota. La interfaz remota para el bean, sin embargo, no esti disponible hasta que vuelva e j b c r e a t e ( ) . Si necesita la interfaz remota durante la creaci6n del componente EJB, n o habria mod0 de proceder. En lugar de dejar este hueco en la especificaci6n, se desarroll6 un mktodo "despuks de crear" en el que la interfaz remota estaria disponible. Este mktodo es e j b c r e a t e p o s t ( ) . La misma situaci6n existe con la clave primaria en la persistencia gestionada por contenedor, porque el contenedor crea la clave. Si la clave primaria se necesita por algun motivo, ese trabajo tambikn necesita ser realizado en e j b p o s t c r e a t e ( ) . tPor quk necesitaria pasar la referencia remota o clave primaria del EJB a otro EJB durante su creacibn? La Gnica buena raz6n que he encontrado es la que justifica la configuraci6n de relaciones, por ejemplo cuando crea a1 empleado del que quiere que el jefe tenga una referencia. En un bean gestionado por contenedor, 10s parimetros que son pasados por el cliente seri utilizados para inicializar el estado del bean de entidad. Aunque el tip0 de retorno del mktodo e j b c r e a t e ( ) es el mismo que la clave primaria, el desarrollador de bean s61o debe devolver n u l l . El contenedor ignorara el valor devuelto, a pesar de todo. La raz6n por la que debe devolver null en el caso de C M P es que la clave seri realmente creada e inicializada por el contenedor basindose en el valor de 10s campos que acaba de inicializar. Quizis se pregunte por quk e j b C r e a t e ( ) devuelve un valor. La raz6n es sutil: de este mod0 puede crear una clase EJB BMP ampliando una clase EJB CMP. Para que esto funcione, la Especificaci6n de Lenguaje Java establece que 10s mktodos que necesitan ser ignorados en la clase secundaria deben tener el mismo tip0 de retorno, de ahi este pequefio truco. En un bean gestionado por bean, el bean debe insertar su estado en el almacen de datos subyacente; para una base de datos relational, esto significa que el desarrollador escribiri una instrucci6n INSERT en SQL. El desarrollador de bean debe utilizar 10s datos para inicializar las variables de estado del bean, except0 en el caso poco usual de que el bean de entidad BMP haya almacenado su estado directamente en la base de

Capitulo 16
datos sin utilizar ning6n intermediario de variable de instancia. (Esto seria como nuestra implementaci6n de bean de sesi6n sin estado de comprador, per0 con identidad implicita.) Finalmente, el desarrollador de bean debe construir una instancia de su clave primaria y devolverla.
La clase de implementation de Sports Team CMP

~ s t es a la versidn C M P de nuestras retrollamadas de creaci6n del bean de entidad del equipo de deporte (ariadiremos a esta clase a medida que vayamos analizando las diversas retrollamadas):
package import import import import import impo r t import import import public s p o r t B e a n . cmp; javar.ejb.+; j a v a x . naming.

*;

]ava.rmi.RemoteException;
j ava .s q l . C o n n e c t i o n ; j a v a . s q l . SQLEsception; j ava. s q l . Preparedstatement; j ava. s q l .P,esultSet; javax.sql.DataSource; java.util.*; abstract class SportTeamEJB e jbCreate
(

implements

EntityBean

publlc

SportTeamPK

String String

sport, nickName)

throws

CreateExceptiun

setSport(sport); s e t N i c k N a m e ( n i c k N a m e ); setOwnerName ( n u l l ) ; s e t F r a n c h i s e P l a y e r ( r ~ u 1 1; ) return null;

I
/ / Podria s e r u t i l i z a d o para r e g i s t r a r que un EJB acaba d e s e r c r e a d ~ , p o r ejemplo
public public vaid e j b F o s t C r e a t e ( S t r i n g key, ejbCreate( String String throws String relatedData)
{

SportTeamPK

s p o r t , S t r i n g nickName, ownerNarne, S t r i n g f r a n c h i s e p l a y e r ) CreateException {

setSport(sport); setNickNarneinickName); setOwnerNarne ( o w n e r N a m e ) ; s e t FranchisePlayer ( f rar1chisePlayer) ; return null;

1
public void e j b P u s t C r e a t e ( S t r i n g s p o r t , S t r i n g nickName, S t r i n g awnerName, S t r i n g f r a n c h i s e P l a y e r )

{I

Asimismo, necesitamos crear accesores abstractos para todos nuestros campos CMP:
abstract abstract abstract abstract abstract abstract public public public public public public S t r i n g g e t s p o r t i ); void s e t S p o r t i S t r i n g sport);

S t r i n g getNickNarne ( ) ; v a i d setNickName ( S t r i n g nickname) ; S t r i n g getOwnerName( ) ; v o i d setOwnerName(Strir1g

ownerName);

Beans de entidad y persistencia

abstract abstract

public public

String getFranchisePlayer ( ) ; void setFranchisePlayer(String franchisePlayer);

La clase de implementacion BMP de SportsTeam


ES

el mismo bean de entidad del equipo de deporte con persistencia gestionada por bean. (De nuevo, afiadiremos a esta clase.). Observe que hay dos diferencias fundamentales:
0

Los metodos e j b C r e a t e de datos

()

tienen c6digo J D B C y SQL para insertar un registro en la base

O El metodo devuelve una instancia de una clave primaria, en lugar del valor nu11
package import imp'irt import import import import import import import public s p o r t B e a n . bmp; javax.ejb.+; j a v a x . naming. *; j a v a . rmi .R e m o t e E x c e p t i o r ~ ; j a v a .s q l . C o n n e c t i o n ; j a v a . s q l . SQLException; j ava. s q l . Preparedstatement; j ava. s q l . Resultset; j avax. s q l . Datasource; j a v a . u t i 1 . +; class SpiirtTeamEJB implements ErltityBean
{

public public ptublic publlc

String sport; S t r i n g nickName; S t r i n g ownerName; String franchisePlayer;

E r ~ t i t y C o r ~ t e xc ttx; publlc SportTeamPK e j b c r e a t e ( S t r i n g s p o ~ t , S t r i n g nickName) this.sport = sport; t h i s . nickName = nickName; ownerName = n u l l ; franchisePlayer = null;

throws

CreateException

C o n n e c t i o n con = n u l l ; try { con = g e t C o n n e c t i o n ( ) ; / / t h i s method i s d i s c u s s e d l a t e r Preparedstatement statement = c o n . p r e p a r e S t a t e m e n t ("INSERT INTO SPORTSTEAMS (SPORT, NICKNAME) " "VALUES ( ? , ?I") ; statement.setString(1, sport); s t a t e m e n t . s e t s t r i n g ( 2 , nickName) ; i f (statement.executeUpdate ( ) != 1) [ t h r o w new C r e a t e E x c e p t i o n ( " F a i l e d t o c r e a t e s p o r t s t e a m . " ) ;
}

1 catch
]

(SQLException s y l e ) ( t h r o w new E J B E x c e p t i o n ( s q 1 e ) ; firtally { try { i f (con ! - n u l l ) { con.close();


I
1

I I

catch

(SQLException s q l e )

{ }

Capitulo 16

return

riew S p o r t T e a m P K ( s p o r t ,

nickName);

I
public void ejbPostCreateiStrinq key, String relatedData)
{ )

public

S p o r t T e a m P K e j b c r e a t e ( S t r i n g s p o r t , S t r i r ~ gn i c k N a m e , S t r i n g ownerName, Strinq franchiseplayer) t h r o w s javax.ejb.CreateException { t h i s . s ~ o r t = sport; t h i s . nickName = n i c k N a m e ; t h i s . o w n e r N a m e = ownerName; t h i s . f ranchisePlayer = franchisePlayer; C o n r ~ e c t l o n con = n u l l ; try I con = getConnectlon ( ) ; Preparedstatement statemer~t= c o n . p r e p a r e S t a t e m e n t ( "INSERT INTO SPORTSTEAMS (SPORT, NICKNAME, "OWNERNAME, FRANCHISEPLAYER ) VALUES " +
"(?, ?,
?,

"

?)"I;

s t a t e m e n t . s e t s t r i n g (1, s p o r t ) ; s t a t e m e n t . s e t s t r i n g ( 2 , nickName); s t a t e m e n t . s e t S t r 1 n g ( 3 , owrlerName) ; statement. setstring ( 4 , EranchisePlayer]; i f (statement.executeupdate ( ) != 1) { t h r o w new C r e a t e E x c e p t i o n ( " F a i 1 e d t o c r e a t e

sports team.");

1 catch
throw

(SQLException s q l e ) { new E J B E x c e p t i o n ( s q l e ) ;

1 finally [ try I i f (con ! = n u l l ) { con. c l o s e ( ) ; i ] c a t c h (SQLException s q l e ) 1 return riew S p o r t ? ' e a m P K ( s p o r t ,

{ )

nickName) ;

I
public void e j b P o s t C r e a t e ( S t r i r 1 g s p o r t , S t r i n g nickName, S t r i n g ownerName, S t r i n g f r a n c h i s e p l a y e r )
{

N o es necesario ariadir 10s accesores para beans de persistencia gestionados por bean, asi que no 10s aiiadiremos aqui, pero es una prkctica que recomendaria en cualquier caso con propdsitos de abstracci6n y tambie'n en caso de que decida cambiar su bean en un futuro a CMP.
Es posible, y en ocasiones apropiado, tener un bean de entidad sin mktodos create ( ) . Un bean de entidad es simplemente una vista orientada a1 objeto sobre datos transaccionales, compartidos. En un entorno con aplicaci6n distintas de EJB, estos datos (y, por consiguiente, estos beans de entidad) pueden existir sin que create ( ) sea invocado. Si estos datos fueran creados 5610 por estas aplicaciones no-EJB, entonces 10s beans de entidad podrian ser escritos sin metodos c r e a t e ( ) . Por ejemplo, nuestros registros de base de datos del equipo de deporte podrian ser creados exclusivamente por alguien con una hoja de cilculo Star Office vinculada a nuestra base de datos, con nuestra aplicaci6n utilizada para mantener informaci6n actualizada sobre propietarios y jugadores franquicia. En este caso, no se requeriria ningfin mktodo c r e a t e ( ) .

Beans de entidad y persistencia

Leer
El metodo de retrollamada ej bLoad ( ) corresponde aproximadamente a la funcionalidad "leer" de beans de entidad. U n modo sencillo de verlo es el siguiente: la entidad cargari 10s datos desde la base de datos en correspondencia con la llamada ej bLoad ( ) del contenedor. Con persistencia gestionada por contenedor, el contenedor EJB se responsabilizari de transferir el estado de la entidad desde la base de datos a las variables de instancia de la entidad. En este caso, el programador de bean a menudo dejari el metodo e j bLoad ( ) en blanco, per0 puede elegir realizar a l g h tip0 de procesamiento posterior de 10s datos cargados. Con persistencia manejada por bean, el programador de bean escribiri su c6digo de acceso a datos (probablemente c6digo JDBC y SQL) en e j bLoad ( ) para transferir el estado de la entidad avariables de instancia. Esta descripci6n es un buen modo de comprender el proceso, per0 no es la historia completa. Tkcnicarnente, ej bLoad ( ) no indica a1 bean que debe en realidad cargar datos: simplemente indica que debe re-sincronizarse con el almackn de datos subyacente. Esta es una diferencia sutil per0 potencialmente importante.

La implernentacion de persistencia del bean puede elegir diferir la carga del estado hasta que el estado sea realmente utilizado.
Consideremos un ejemplo. U n bean de entidad Pedido puede tener un numero de pedido, un nombre de comprador y una lista de articulos de linea. Cuando se invoca e j bLoad ( ) para un bean de entidad que representa un pedido concreto, el estado de ese pedido (nlimero, nombre y articulo de linea) debe ser sincronizado con la base de datos. En este ejemplo, lo 16gica de persistencia puede elegir actualizar el nombre y el numero inmediatamente desde la base de datos. N o obstante, recuperar la lista de articulos de linea relacionados en una operacion potencialmente cara, por lo que, en su lugar, se establece un indicador "sucio". Si el unico metodo invocado en este bean de pedido es getCustomerName ( ) , 10s articulos de linea nunca necesitarin ser cargados. Cualquier metodo que deba acceder a la h a , como totalLineItems ( ) ,por ejemplo, necesitari comprobar el indicador sucio y cargar la lista desde la base de datos si esti configurada.
Crear la tabla

En primer lugar, creemos la tabla que contendri nuestro bean de entidad. Las siguientes instrucciones SQL deben ser emitidas desde su base de datos:
CREATE TABLE SPORTSTEAMS ( SPOhT VARCHAR ( 25 ) NOT NULL, NICKNAME VARCHAR (25) NOT NULL, OWNERNAME VARCHARIZS), FRANCHISEPLAYER VARCHAR(25)) ;

~ s t es e SQL estindar, por lo que deberia funcionar en casi cualquier base de datos. Si no es asi, consulte su documentaci6n.
Beans de entidad CMP y ejbLoadO

La funci6n de e j bLoad ( ) en la persistencia gestionada por contenedor es procesar 10s datos despues de que hayan sido cargados desde la base de datos. A menudo, 10s datos no necesitarin ningun tip0 de procesamiento y su metodo e j bLoad ( ) estari vacio. En ocasiones, sin embargo, seri necesario realizar algunos cambios. U n ejemplo prictico: puede almacenar sus datos string en campos debase de datos char de un cierto tamaiio y la base de datos puede aiiadir espacios en blanco a sus cadenas para alargarlas hasta la longitud correcta. Aunque esto puede resultar mis eficiente que utilizar un tip0 de datos varchar,esos espacios en blanco pueden resultar molestos. Podria utilizar e j bLoad ( ) para recortar esos espacios en blanco. Puesto que hemos utilizado VARCHAR para crear nuestra tabla, e j bLoad ( ) estari vacio en nuestro ejemplo CMP:

Capitulo 16
public void ejbLoad()
{

Beans de errtidad BMP y ejbLoadO

La funci6n de ej bLoad ( ) en la persistencia gestionada por bean es notificar a1 bean que debe invalidar el presente estado almacenador en cache y prepararse para invocaciones de metodo de empresa. En terminos pricticos, esto significa normalmente sustituir el estado cargindolo desde la base de datos. Para encontrar 10s datos del bean de entidad en la base de datos, necesitari la clave primaria. Cuando se invoca ej bLoad ( ) ,la clave primaria ya ha sido asociada a la entidad y esti disponible desde su contexto. Este contexto de entidad es asociado a1 bean con un metodo de retrollamada, igual que el contexto de sesi6n se asocia a un bean de sesi6n. La interfaz EntityContext es la siguiente:
package public javax.ejb; interface EntityContext extends EJBContext
{

public abstract EJBLocalObject getEJBLocalObject0 throws IllegalStateException; public abstract EJBObject getEJBObject0 throws IllegalStateException; public abstract Object getPrimaryKey throws IllegalStateException;
()

U n bean que utiliza persistencia gestionada por bean necesitaria utilizar el contexto de entidad para recuperar su clave primaria asociada a la implementaci6n de ej bLoad ( ) ,utilizando el par de retrollamadas setEntityContext ( ) /unsetEntityContext ( ) cuando son invocadas el contenedor para guardar el contexto de identidad para su uso. Atiada 10s siguientes metodos s61o a la versi6n de persistencia gestionada por bean del bean de entidad del equipo de deporte:
public void
thj s.ctx

s e t E n t i t y C o r ~ t e x (tE n t i t y C c ~ r i t e x t c t x ) = ctx;

1
// //
E l c o n t e n e d o r i n v o c a r 6 e s t e metodo. C u a l q u i e r r e c u r s o q u e a s i g n e erj s e t E n t i t y C o n t e x t ( ) d e b e s e r l i b e r a d o a q u j ( ) { public void unsetEntityContest ctx = null;

La implementation para estos mitodos puede estar vacia para la versi6n de persistencia gestionada por contenedor:
publie pub1 i c void void s e t E n t i t y C o n t e x t ( E n t i t y C o r ~ t e x tct:<i u n s e t E n t i t y C o r ~ t e x (t )
[

{ ]

~ s t es a la versi6n BMP de ej bLoad ( ) para el bean del equipo de deporte. Fijese en c6mo utilizamos el contexto de entidad guardado para recuperar la clave primaria:
public void ejbLoad( ) [ SportTeamPK prlmaryKey Connection con = n u l l ; try { con = g e t C o n n e c t i o n (
=

(SportTeamFK) c t s . g e t P r i m a r y K e y 0 ;

) ;

Beans de entidad y persistencia


Freparedstatement statemer~t = con. preparestatement ("SELECT OWNERNAME, FRANCHISEPLAYER "FROM SPORTSTEAMS WHERE SPORT = ? "AND NICKNAME = ? " ) ; s t a t e m e n t . setstrirlq ( 1 , primaryKey.getSport ( 1 ) ; s t a t e m e n t . s t t S t r i n q ( 2 , primaryKey.yetHickName() 1 ; Resultset resultset = statement.esecuteQuery( ) ; if ( ! r e s u l t S e t . n e z t( ) ) { t h r o w riew EJBExceptior~ ("Object r~ot fourld. " ) ;

"
"

I
sport = primaryKey.getSport(); nickName = primaryKey .qetNickName ( ) ; owrjerName = resultSet.qetStrinq ( 1 ) ; frar~chisePlayer = resultset .getStrirlg ( 2 ); resultSet.cldse(); s t a t e m e n t . close ( ) ; catch (SQLExceptirsrj s q l e ) { throw rjew EJBExcept ion ( s q l e ) ; finally { try i if ( c o n ! = null) { con.close ( ) ; i } catch (SQLExceptiorb sqle) { I

Actualizar
El metodo de retrollamada e j bs t ore ( ) corresponde aproximadamente a la funcionalidad "actualizar" de 10s beans de entidad. Por supuesto, la modificaci6n real del estado almacenado en cache del bean de entidad se realizari a traves de llamadas a metodos de empresa, como setShipmentAddress ( ) o calculateSalesTax ( ) . El contenedor invocari el metodo e j bstore ( ) para notificar a1 bean que debe sincronizar su estado con la base de datos. Para un bean con persistencia gestionada por contenedor, este metodo sera invocado directamente antes de que el contenedor escriba el estado de bean alterado en la base de datos y el programador de un bean CMP puede aprovechar esta oportunidad para pre-procesar 10s datos del bean y garantizar que es un estado apropiado para almacenamiento persistente. Habitualmente, sin embargo, este metodo quedari vacio. Para un bean con persistencia gestionada por bean, el programador es responsable de proporcionar en este metodo la logica que transferira el estado del bean a1 almacen de datos subyacentes. Para una base de datos relational, esto significari normalmente que el programador de bean escribiri c6digo JDBC e instrucciones UPDATE SQL.
Con e j bLoad (), el bean tiene la opci6n de diferir la verdadera carga de estado basta que sea utilizado. N o existe esta opcidn con e j b s t o r e (). Cualquier modificaci6n sobre el estado del objeto debe ser escrita inmediatamente en el almacenamiento de datos. La optimizacidn equivalente es probablemente algo denominado "actualizaciones ajustadas". En otras palabras, s61o es necesario escribir el estado modificado; si algo no ha cambiado, puede dejarlo solo.
CMP y el d o d o ejbStore0

Como ocurre con e j bLoad ( ) , el metodo e j bstore ( ) para nuestra versi6n CMP del bean SportTeam esti vacio:
public void ejbstorei )

iI

Capitulo 16
BMP y el d t o d o ejbStoreO

~ s t es e e j b s t o r e ( ) para el bean de entidad del equipo de deporte con persistencia gestionada por bean. Observe que no es necesario que recuperemos la clave primaria del context0 de entidad (aunque podriamos hacerlo) porque la informacion esti disponible para nosotros en las variables de instancia de esta clase:
public void e j b S t o r e ( ) I C o n n e c t i o n con = n u l l ; try I con = q e t C o n n e c t i o n ( ) ; Preparedstatement statement = c c . n . p r e p a r e S t a t e m e n t ("UPDATE SPORTSTEAMS SET OWNERNAME=?, " "FRANCHISEPLAYER=? WHERE SPORT = ? " " A N D NICKNAME = ? " ) ; s t a t e m e n t . s e t S t r i n g ( l , owr~erName); statement .setStrirjg ( 2 , franchiseflayer); statement .setString(3, s p c ~ r t ) ; s t a t e m e n t . s e t s t r i n g ( 4 , nickName) ; if
I

(statement .executeupdate ( ) != 1) 1 t h r o w new E J B E x c e p t i o n ( " F a i 1 e d t o s a v e o b j e c t

state.");

s t a t e m e r ~ tc .lose ( ) ; c a t c h (SQLException s q l e ) { t h r o w new E J B E x c e p t i o n ( s q l e ); finally { try i i f (con != n u l l ) ( con,. c l o s e ( ) ;


1

)
1

catch

(SQLException s q l e )

{ }

Eliminar
Cuando un cliente invoca r e m o v e ( ) sobre un bean de entidad, 10s datos son eliminados del correspondiente almacen de datos. Por el contrario, cuando un cliente invoca r e m o v e ( ) para un bean de sesion con estado, el contenedor EJB descarta la instancia de bean de sesi6n del almacenamiento temporal del servidor de la aplicaci6n. Es importante entender esta diferencia. Siempre debe invocar r e m o v e ( ) cuando haya terminado de utilizar un bean de sesi6n con estado; si no lo hace asi, el contenedor EJB malgastari 10s recursos que gestionan esta instancia.
N o debe invocar remove ( ) sobre un bean de entidad a menos que desee eliminar ese registro. El contenedor EJB gestionari la instancia del bean de entidad en el contenedor. CMP y el d t o d o remove0

Para un bean de entidad con persistencia gestionada por contenedor, el metodo e j bRemove ( ) puede dejarse vacio normalmente y el contenedor manejari la eliminacion de la instancia del almacen de datos subyacente. El programador de un bean de entidad con persistencia gestionada por contenedor puede utilizar este metodo para implementar cualquier acci6n que deba ser llevada a cab0 (como actualizar datos relacionados o ?otificar a otros sistemas) antes de que la representation de objeto entidad sea eliminada de la base de datos. Este es el metodo para nuestro bean del equipo de deporte con persistencia gestionada por contenedor:
public void ejbRemove0
{ }

Beans de entidad y persistencia


BMP y el m6todo remove0 Para un bean de entidad con persistencia gestionada por bean, el programador es responsable de proporcionar la 16gica que elirninari el objeto del recurso subyacente. Para una base de datos relational, esto significari habitualmente que el prograrnador de bean escribiri c6digo JDBC e instrucciones DELETE SQL.

Observe que, corno con cualquier rne'todo de ernpresa, 10s datos sera'n cargados por el contenedor (invocando e j b L o a d 0 )antes de que se invoque e j b R e m o v e 0 . Esto perrnite a/ programador ejecutar la validacidn de la solicitud de elirninacidn y actualizar datos o sisternas relacionados, sin cargar 10s datos independienternente de la retrollarnada del contenedor EJB.
~ s t es a la versi6n con persistencia gestionada por bean:
p u b l i c v o i d e j bRemove ( ) t h r o w s j a v a x . e j b . R e m o v e E x c e p t i o n { Connection con = n u l l ; try I con = g e t C o n n e c t i o n I ) ; PreparedStatement statement = c o n . p r e p a r e S t a t e m e n t ( "DELETE F R O M SPORTSTEAMS " t "WHERE SPORT = ? A N D NICKNAME s t a t e m e n t . s e t S t r i n g (1, s p o r t ) ; s t a t e m e n t . s e t s t r i n g ( 2 , nickName) ; i f (statement.executeupdate ( ) != 1) { t h r o w new E J B E x c e p t i o n ( " F a i l e d t o r e m o v e

");

object.

'I)

i
}

s t a t e r n e r ~ tc .lose ( ) ; c a t c h (SQLException s q l e ) { t h r o w new E J B E x c e p t i o n ( s q l e ) ; finally { try i i f (con != n u l l ) { con. c l o s e ( ) ;

1
)

catch

( SQLException

sqle

t 1

Retrollamadas BMP versus retrollamadas CMP


Las firmas de las retrollarnadas de crear, leer, actualizar y elirninar son las misrnas para persistencia gestionada por bean y persistencia gestionada por contenedor. Las implementaciones, sin embargo, son rnuy diferentes:
0

Para beans de entidad con persistencia gestionada por bean, estas retrollarnadas son responsables de resolver el problema completo de sincronizaci6n de estado con el alrnacCn subyacente de datos para crear, leer, actualizar y elirninar. excepci6n de 10s rnCtodos e j bcreate ( ) ) son sirnplemente utilizadas para "matizar" las operaciones del contenedor. Todas las operaciones relacionadas con el alrnacenarniento y recuperacidn de estado de la base de datos serin realizadas por el contenedor, pero quizis desee realizar otras tareas cuando esto suceda (corno registrase, adquirir o liberar recursos, etc.).

o Para beans de entidad con persistencia gestionada por contenedor, estas retrollamadas (con

Para aclarar las diferencias, Csta es una irnplementaci6n tipica de estas retrollarnadas para un bean de entidad gestionado por contenedor:
public Strirtg e j b c r e a t e ( S t r i n g key, String relatedData 1
[

Capitulo 16
thi:.I:ey = key; t h i s . relate'jData

relate(3Data;

publiz

void

t j b f ' < > s t C r e a t e [ S t r i n g Izey,


ejbload ( )
{

String

relatednatal

[I

p ~ b l i cv o i d public woid

1
[

t j bRemi8ve ( )

Observe que hay un coste de desarrollo muy reducido, un coste de mantenimiento muy reducido y muy poco espacio para el error en la implementacion de estos metodos. Esto es parte de lo que le proporciona la persistencia gestionada por contenedor.

El descriptor de implernentacion
Para estar especificado por complete, un Enterprise JavaBeans debe estar acompaiiado de a1 menos un INF A - en el descriptor de implementaci6n, llamado e j b- j a r .xml (y almacenado en un d i r e c t o r i o ~ ~ ~ archivo JAR). Mientras que la especificaci6n EJB 2.0 s61o establece la existencia de un descriptor, no es suficiente para proporcionar en realidad informaci6n suficiente a1 contenedor para implementar el EJB. El motivo es que e j b- j a r .xml esti intentando permanecer tan neutral como sea posible con relacion a 10s medios de implementaci6n que serin utilizados para ejecutar ciertas operaciones. Por ejemplo, la siguiente informaci6n no forma parte de e j b- j a r .xml:
O Nombre J N D I de la interfaz inicial remota

0 Nombres J N D I de 10s destinos utilizados por beans controlados por mensaje


0 Nombres de las tablas utilizadas por beans de entidad CMP 0 Reservas de conexi6n utilizadas por beans de entidad C M P 0 0

Q u e columnas de la tabla se asocian a quC campos de beans CMP Otros recursos

Esta informaci6n debe, por lo tanto, ser provista de forma separada. Los contenedores habitualmente esperarin a que introduzca esta informaci6n en otro descriptor de implementaci6n. Por ejemplo WebLogic de BEA buscari un descriptor l l a m a d o w e b l o g i c - e j b- j a r - x m l . Si su archivo JAR contiene beans de entidad CMP, tambiCn se le pediri que proporcione un descriptor de implementaci6n extra que contendri exclusivamente informaci6n relacionada con CMP. El nombre de este tercer descriptor es de su eleccibn, per0 es necesario que lo referencie e n w e b l o g i c - e j b- j a r .xml. Observe queen realidad puede tener un numero arbitrario de descriptores de implementacidn CMP per0 s61o utilizaremos uno en este libro, para una mayor sencillez. Para resumir, un archivo JAR (desplegable) legal contendri 10s siguientes descriptores de implementaci6n:
U U n e j b - j a r .xml (asignado por la especificaci6n EJB 2.0)
0 U n w e b l o g i c - e j b- j a r xml (requerido

WebLogic)

U n o o mis archivos XML C M P (s610 necesarios si tiene beans de entidad CMP y 10s nombres de estos archivos deben ser especificados e n w e b l o g i c - e j b - j a r . xml) Las siguientes secciones ilustrarin todos estos descriptores de implementaci6n.

Beans de entidad v persistencia

Persistencia en 10s descriptores de implernentacion


El tip0 de persistencia (gestionada por bean o gestionada por contenedor) es especificada en el descriptor de implementaci6n para el EJB. El elemento < p e r s i s t e n c e - t y p e > del descriptor de implementaci6n seri uno de 10s siguientes:

Si la persistencia del bean esti gestionada por el contenedor, 10s campos persistidos deben ser tambien especificados en el descriptor. Cada entrada del descriptor de implementaci6n tiene el nombre del campo en la clase y puede t a m b i h tener una descripcibn. Este es un ejemplo de dos campos de la versi6n C M P de nuestro bean de entidad del equipo de deporte (generando una descripcidn opcional):
<cmp-field> <f i e l d - r ~ a m e > s p o r< t / field-name> < d e s c r i p t i , ~ ' r ~ > L i kb ea s k e t b a l l o r c r i c k e t . < / d e s c r i p t i o n > </cmp-f i t l d > <cmp-field, <f ield-name>nickName</field-r~ame> </cmp-field>

Los campos gestionados por contenedor del descriptor de implementaci6n deben declararse en la clase de bean como accesores, como vimos anteriormente. Ambos mktodos, g e t y s e t , deben ser proporcionados. N o olvide poner en mayfiscula la primera letra de su campo en el nombre del metodo: asi, el campo C M P n i c k ~ a m se e convierte en g e t N i c k N a m e ( ) / s e t N i c k N a m e ( ) en su clase bean.

EI descriptor de implementaci6n e j b- j a bean es el siguiente:

r xml

pricticamente completo para la versi6n CMP de nuestro

"!DOCTYPE e j b - l a r PUBLIC " - / / S I I ~ M i c r o s y s t e m s ,

Inc.//DTD

"http://]ava.sun.com/dtd/ejb-jar

E n t e r p r i s e JavaBeans 2 O.dtdW>

2.0//ENM

/er~tity> b1 -r~amei < e jb - r ~ a m e > C M P S p o r t s B e a r 1 < / ~ < h o m e > s p o r t B e a r ~c.m p . S p o r t T e a m H o m e < / h ~ m e > < r e m o t e > s p o r t B e a r ~c .mp. S p o r t T e a m < / r e r n c o t e > < e j b - c l a s s > s p o r t B e a r ~c .mp. S p i ~ r t T e a n 1 E J B ~ / t ] b - ~ l a s s > <ptrsister~ce-type>Cor~tair~er</persister~ce-type> < p r i m - k e y - c l a s s > s p o r t B e a r l . cmp. S p i ' r t T e a r r ~ P K ' / p r i r r ~ - k e y - c l a s s > <reer~trar~t>False</reer~trar~t>

<cmp-version>2.x</cmp-versinn>
Another element ir, here, we'll s e e t h i s i n t h e f i r d e r <cmp-field><field-r~ame>sport</f ielId-rlar~e></cr~pif eld>
<!-

s e c t i o r ~>

<cmp-field><field-name>r~ickName</field-r~arr~e></cmp-field> <cmp-field><field-name>owr~erNan~e~/fi~ld-r~ame></cmp-field> <cmp-field><field-name>frar~chisePlay~r</field-r~ame></cmp-field>


< ! More </entity>

elements

to

be

added

here

Capitulo 16

Todavia queda por afiadir a1 descriptor de implementacibn CMP, corno elernentos para representar el bean BMP en el rnismo archivo.
ES la porci6n del descriptor de irnplernentacibn e j b- j a r .xml para la versi6n con persistencia gestionada por bean. N o tiene elernentos t c m p - f i e l d > per0 declara que utilizamos un recurso (la conexibn JDBC, declaradaenelelernento<resource-ref>):

< e n t l t y> < e j b - n a m e > C M P S p e r t s B e a r ~ < / e b-name> j < ! - R e s t uf d e p l o y m e n t , d e s c r i p t u r f o r CMP </entity>

not

shown >

<assembly-descriptor> < ! - R e s t of d e p l o y m e n t

descriptor

for

CMP

not

shown

>

</assembly-descriptor:, </ejb-jar>

Almacenamiento en memoria cache


Una cachk es una copia secundaria de datos realizada habitualrnente por rnotivos de rendirniento o conveniencia. Las variables de instancia de su bean de entidad que representan el estado persistente del

Beans de entidad y persistencia


objeto son en realidad una cache de 10s datos cuya localization en el almacenamiento permanente se encuentra en su base de datos. Por ejemplo, en su bean de entidad Comprador puede tener tres variables de cadena para el nombre, el segundo nombre y el apellido del comprador. Estas tres variables podrian ser copias secundarias de 10s datos de tres cplumnas de una tabla de base de datos relational llamada customer: fname,mname y lname.Esta es una tabla sencillaparaaclarar este ejemplo: Datos Copia primaria Columna de base de datos fname Columna de base de datos lname Copia cachetizada Campo de bean de entidad fname Campodebeandeentidadmname Campo de bean de entidad lname

I
(

Primer nombre del comprador Apellido del comprador

Segundo nombre del comprado Columna de base de datos mname

La cache consistente en las variables de instancia de su bean de entidad sufriri el mismo problems potencial que cualquier cache: puede abandonar la sincronizaci6n con la copia primaria de 10s datos. Para continuar con nuestro sencillo ejemplo del comprador, el registro de la base de datos puede tener el lname "Smith" despuis de una actualizaci6n realizada por un sistema de gesti6n de compradores, per0 el correspondiente campo de bean de entidad puede que todavia tenga el nombre anterior de Yones". C o n ambas persistencias, BMP y CMP, hay una responsabilidad combinada entre el contenedor EJB y el almacen subyacente de datos de gestionar la sincronizaci6n del cache de una entidad. El tema de almacenamiento en cache esti intimamente relacionado con las retrollamadas C.R.U.D. y la transferencia de un estado de objeto entidad hacia y desde el almacin de datos persistentes. El contenedor EJB invocari e j bLoad ( ) y e j bStore ( ) cuando considere necesario mantener la cachi local en sincronizaci6n con la copia primaria de 10s datos. Como programador de bean, n o es necesario que se preocupe por saber cuindo exactamente invocari el contenedor e j bLoad ( ) y e j bS tore ( ) . Debe estar preparado para que la invocaci6n de mitodo tenga lugar en cualquier momento entre mitodos de 16gica de empresa. Sin embargo, esti bien comprender las estrategias comunes que emplearin 10s contenedores EJB en diversas situaciones, de mod0 que puede tomar decisiones informadas sobre servidores de aplicaci6n, implementaci6n, etc. Supongarnos que un cliente quiere utilizar una copia de nuestro bean de comprador de tres campos. Quiere invocar dos metodos sobre el bean: set FirstName ( ) y setMiddleName ( ) . Hay dos casos diferentes que debemos considerar, dependiendo de si estos mitodos son o no invocados en la misma transacci6n:
O En el primer caso, estos dos metodos son invocados en la misma transaccibn.

Antes de que se invoque el primer metodo de 16gica de empresa, el contenedor o el bean (dependiendo de CMPversus BMP) cargari el estado desde la base de datos c ~ r r e s ~ o n d i e n con do una llamada a e j bLoad ( ) . Ahora es invocado el mitodo de ernpresa set Firs tName ( ) . En este punto, el contenedor tiene la opci6n de invocar de nuevo e j bs tore ( ) y e j bLoad ( ) ,antes de invocar setMiddleName ( ) . Podria hacerlo si fuera parte de un cluster de servidor de aplicaci6n y no pudiera garantizar que la misma instancia de bean de entidad fuera utilizada para ambos mitodos de empresa. Sin embargo, en el caso m6s combn, simplemente continuaria e invocaria el mitodo setMiddleName ( ) . Puede hacer esto porque ambos mitodos son parte de la misma transacci6n y las transacciones estin disehadas para garantizar que las modificaciones realizadas a un almacin de datos estin aisladas de otras actividades en esos datos. En otras palabras, e j bLoad ( ) y e j bstore ( ) serin invocados para objetos entidad en fronteras de transacci6n. (Observe que no esti establecido por la especificadn; es simplemente una estrategia combn de implementaci6n.)
3 En el segundo caso, estos dos mitodos son invocados en diferentes transacciones.

De nuevo, antes de ser invocado el primer metodo de 16gica de empresa, el contenedor o el bean cargarin el estado desde la base de datos c ~ r r e s ~ o n d i e na te una llamada a e j bLoad ( ) . Una vez ha sido invocado set FirstName ( ) ,la transaction conchye y se invoca e j bS tore ( ) para

Capitulo 16
actualizar el alrnacCn de datos. Ahora se invoca setMiddleName ( ) . En el caso general, el contenedor EJB sirnplernente repetiri el proceso, invocando e jbLoad ( ) y e jbStore ( ) alrededor de la invocaci6n de setMiddleName ( ) . La cache debe ser resincronizada con e jbLoad ( ) porque, entre las dos transacciones, algun otro proceso o aplicaci6n podria haber rnodificado 10s datos. Hay, sin embargo, dos casos especiales que pueden perrnitir a1 contenedor EJB evitar la invocaci6n del metodo e jbLoad ( ) sobre la instancia de entidad a1 cornienzo de las transacciones posteriores a la prirnera llarnada de metodo:
O El primer0 consiste en que todos 10s accesos a 10s datos pasan a travis del contenedor EJB y de

ese bean de entidad. Si este fuera el caso, entonces el contenedor sabe que la cache del bean de entidad y 10s datos del alrnackn persistente de datos estin sincronizados. Cada carnbio realizado a 10s datos tendri lugar en la cache antes de reflejarse en el alrnacen de datos, si todo acceso es a traves del bean. Sin embargo, si se utiliza una tecnologia distinta de EJB para rnodificar 10s datos (un sisterna ERP), entonces no puede utilizarse este enfoque. Esto se debe a que no hay nada que garantice que 10s datos no carnbiarin sin que el contenedor y el EJB lo sepan.
O

El segundo caso se da cuando la aplicacidn concreta no necesita en absoluto 10s ultirnos datos. Obviarnente, esto no se aplica en el caso de un sisterna bancario que debe rnantener inforrnaci6n de contabilidad en sincronizacion. Sin ernbargo, seri el caso de un sorprendente nurnero de sisternas (corno un sisterna de cornercio electr6nico). Los datos guardados en cache se podrian configurar para expirar despuks de un cierto period0 de tiernpo y serian actualizados despues de ese periodo. Si 10s precios para productos fueran modificados por a@n software de gesti6n de dernanda distinto de EJB, este carnbio n o se reflejaria inrnediatarnente en la aplicacion. DespuCs de que expiraran 10s datos alrnacenados en cache (digarnos en cinco rninutos), se reflejaria. Las consecuencias (un retraso de cinco rninutos en precios rnodificados) seria probablernente insignificante.

Si su servidor de apkaci6n proporciona esta optirnizaci6n de datos en cache entre transacciones, lo configuraria con una herrarnienta de configuraci6n especifica de servidor de aplicaci6n. Habitualrnente, la optirnizacidn esti disponible si indica que el contenedor EJB tiene "acceso exclusivo a la base de datos" o similar (por ejernplo, WebLogic 6.1 ofrece una arnplia garna de estrategias de bloqueo, desde "acceso exclusivo a la base de datos" hasta "no ejecutar ningun bloqueo, aplazindolo a la base de datos". Aunque el contenedor EJB puede optirnizar llarnadas e jbLoad ( ) a1 principio de una transacci6n, nunca puede hacerlo para e jbs tore ( ) en la conclusi6n de la transacci6n. La especificacidn Enterprise JavaBeans 2.0 requiere absolutarnente que e jbstore ( ) sea invocado cuando se complete una transacci6n en la que esti participando el bean de entidad. Esto se debe a que uno de 10s A C I D garantiza que un sisterna transaccional hace que una transacci6n sea duradera. Si 10s datos rnodificados son albergados en una cache temporal en el bean de entidad y el bean de entidad es posteriorrnente destruido antes de que tenga la oportunidad de escribir finalrnente sus datos en un alrnacin perrnanente, la parte "duradera" de la garantia transaccional ha sido violada. Esto puede suceder porque una llarnada posterior a1 bean haya provocado una excepci6n de n o aplicaci6n o incluso porque falle el servidor de la aplicaci6n. iQuC sucede en caso de n o carnbie ningun dato? En este caso, puesto que todos 10s accesos de carnpo pasan por accesores generados por el contenedor EJB, sabe que el bean de entidad esti sin rnodificar y la operation ej bstore ( ) seri una operaci6n vacia. Un bean que utiliza persistencia gestionada por bean debe irnplernentar una estrategia para determinar si 10s datos han carnbiado. Una posibilidad es simplernente rnantener un indicador "rnodificado", que es cornprobado en el mitodo e jbstore ( ) para ver si es necesario ernprender alguna acci6n. Otra posibilidad es rnantener copias de 10s datos "antes" y "despuCs", y cornpararlas para construir una instruccibn UPDATE que s61o afecte a 10s datos que han cambiado.

Beans de entidad y persistencia

Los beans de entidad representan datos compartidos. Si estos datos son compartidos, debe haber algfin mecanismo para que 10s clientes obtengan acceso a un determinado bean de entidad. Observe que este problema n o surge con 10s beans de sesi6n; el cliente obtiene acceso al bean cuando Cste es creado y nadie mis lo utiliza nunca. U n bean de entidad, por otro lado, puede ser creado por un cliente y utilizado por cualquier nfimero de clientes completamente diferentes (en este caso concreto, tendremos diferentes instancias del EJB per0 manipulan 10s mismos datos en la base de datos). Cada uno de estos clientes deben ser capaces de encontrar el bean que estin buscando. C o m o sohci6n para este problema, la especificacion Enterprise JavaBean define un mecanismo llamado metodo buscador. U n o o mls de estos metodos buscador son declarados en la interfaz inicial del bean de entidad, uno para cada modo de localizar ese objeto entidad o una colecci6n de ese tip0 de objetos entidad. Estos metodos buscador siguen una cierta convenci6n de nombre: todos empiezan con el prefijo find. Algunos ejemplos s o n f i n d ~ p e n ~ c c o u n0 ts , f indOrdersByDate ( ) o f i n m a n a g e r F o r Empl o y e e ( ) . Pueden adoptar cualquier parimetro necesario para especificar 10s detalles de la busqueda, siempre que esos parimetros sigan las reglas normales para RMI-IIOP (la regla principal, como ya hemos mencionado, es que necesitan implementar j a v a . i o . S e r i a l i z a b l e , ya sea un tip0 primitivo o una interfaz remota). Los metodos buscadores que tendrin como miximo un resultado, tendrin un tip0 de retorno de la interfaz remota para ese bean de entidad. Por ejemplo, el metodo f i n d M a n a g e r F o r E m p l o y e e ( ) definido en unaclasecom. s o m e c o m p a n y . p e r s o n n e l .ManagerHome podria tenerun tipo de retorno de com. s o m e c o m p a n y . p e r s o n n e l . M a n a g e r (y, por supuesto, un parimetro de t i p o ~ m p l o y e e ) (El . m i t o d o f i n d B y P r i m a r y K e y ( ) en cualquier bean de entidad es un ejemplo de este tipo de buscador.) Los metodos buscador que pueden tener cero o mis resultados tendrin un tip0 de retorno java . u t i l .Enumerationojava. u t i l . C o l l e c t i o n . (ElmCtodofind~~~wner~ ( )aesun me ejemplo de la interfaz SportTeamHome.) Si se requiere compatibilidad con JDK 1.1, debe elegirse E n u m e r a t i o n . D e n o ser asi, probablemente sea mejor devolver una C o l l e c t i o n , que proporciona una interfaz rnis flexible a 10s resultados. Ademis de la excepci6n j a v a r m i R e m o t e E x c e p t i o n generada por todos 10s mCtodos remotos, cada metodo buscador tambien debe declarar que genera la excepci6n j a v a x . e j b . F i n d e r E x c e p t i o n . Si un buscador del tip0 que tiene como miximo un resultado n o encuentra ninguna entidad que coincide, el metodo generarl una subclase de la clase F i n d e r E x c e p t i o n : una instancia de j a v a x . e j b .Ob j e c t N o t F o u n d E x c e p t i o n . si un buscador del tipo que tiene cero o mis resultados n o encuentra ninguna entidad coincidente, el metodo simplemente devolveri una coleccidn vacia o una enumeraci6n con cero elementos. Cada bean de entidad debe declarar un cierto buscador "conocido" llamado f i n d B y P r i m a r y K e y ( ) ,que toma un unico parimetro del mismo tip0 que la clase de clave primaria de la entidad. Este buscador devolveri la instancia del bean de entidad con esa clave primaria o generari una excepci6n Ob j e c t N o t F o u n d E x c e p t i o n . Los buscadores adicionales rnis alli d e f i n d ~ ~ ~ r i m a r (y) ~ son ey opcionales. Algunas entidades n o tendrin otros buscadores; otros pueden tener varios.

Implementation de metodos buscadores


La implementaci6n de la 16gica de buscador sera proporcionada por el contenedor EJB para beans con persistencia gestionada por contenedor y el desarrollador de bean n o necesita escribir c6digo Java de apoyo de ningGn tipo. Sin embargo, obviamente n o hay informaci6n suficiente en la firma del metodo buscador para que el contenedor detecte el intento del buscador e implemente la 16gica. t C 6 m o sabria un contenedorc6moimplementarf i n d M o s t ~ ~ ~ r o ~ i a t e ~ a r e ( hP oru os du ec t p r o d u c t , D a t e d a t e N e e d e d ) ? C o m o veremos en las siguientes secciones, Q L EJB r e a h a esta tarea.

Capitulo 16
Para beans de entidad con persistencia gestionada por bean, el desarrollador EJB debe proporcionar una irnplernentaci6n Java de cada bgica en la clase de implernentaci6n del bean. Este metodo tendri parirnetros identicos y tendri un nornbre coincidente de la siguiente convenci6n: si el metodo buscador es f indXXX ( ) , la irnplementaci6n de ese metodo seri llarnada e j bFindXXX 0. El tipo de retorno para un metodo buscador que tiene corno rniximo un resultado seri una instancia de la clase de clave prirnaria para esa entidad y el tip0 de retorno para una irnplernentaci6n de metodo buscador que tiene cero o mis resultados sera una irnplernentaci6n concreta de C O l ~ e c t i o n , o una E n u m e r a t i o n , dependiendo del tip0 de retorno del correspondiente metodo buscador de la interfaz inicial. Los elernentos contenidos en la C O l ~ e c t i o n o devueltos por E n u m e r a t i o n serin instancias de las clases de clave prirnaria para las entidades correspondientes. Observe que la irnplementaci6n de f i n d B y P r i m a r y K e y ( ) tomari una clave prirnaria corno parirnetro, cornprobari que el registro de base de datos existe realmente y devolveri esa rnisrna clave prirnaria corno resultado, si existe. Aunque el contenedor EJB ya tiene la clave prirnaria para este metodo buscador concreto, se solicita a1 desarrollador EJB que lo devuelva en cualquier caso, de mod0 que su uso sea coherente con otros buscadores que devuelven corno rnixirno un resultado. N o tiene ning6n acceso significativo a las variables de instancia relacionadas con estado en la irnplernentacidn de un metodo buscador, ni ninguna otra inforrnacion especifica de la identidad. U n bean de entidad que es utilizado para un metodo buscador no seri asociado a una instancia concreta de estado en la base de datos. Esto difiere de la rnayoria del resto de metodos de bean de entidad, corno 10s rnetodos de ciclo de vida y 10s rnetodos de ldgica de ernpresa. Aunque no debe ser declarado estitico, puede considerar que tiene la rnisrna funci6n que un metodo estitico de factoria en una clase Java distinta de EJB.
CMP y d o d o s buscadores

Observe que para la versi6n CMP, necesitari proporcionar c6digo Q L EJB a1 contenedor de rnodo que pueda generar 10s rnetodos buscadores en su nornbre. El siguiente fragrnento de e j b- j a r .xml asi lo hace (no tiene que proveer f i n d B y P r i m a r y K e y ( ) , sera generado autorniticarnente por el contenedor):
<reentrant>False</reerttrar~t> <cmp-version>2.~</cmp-version>
<abstract-schema-r~ame>SportEJB</abstract-schema-r~ame>

<cmp-field><field-r~ame>sport</field-r~ame></cmp-field>
Other cmp-fields > <query> <query-method> < m e t h o d - n a m e > f indByOwr~erName</method-name> <method-params> <method-param>java. lartg. Strirtg</method-param> </method-params> </query-method> < ej b - q l > < ! [CDATA[SELECT OBJECT ( 0 ) F R O M S p o r t E J B AS o WHERE o.owrierName = ? l ] 1> < / e j b-ql> </query>
<!-

Puesto que es la primera cliusula real Q L EJB que utilizarnos, examinernosla detalladarnente.

SELECT OBJECT ( 0 ) define el tip0 de objeto que estarnos devolviendo. Puesto que estarnos definiendo un buscador, tiene que devolver un EJB del mismo tip0 corno 10s devueltos por 10s rnetodos create() del inicio (en este caso, S p o r t E J B ) . OBJECT ( 0 ) no tiene ning6n significado concreto en Q L EJB per0 es estindar en SQL y el cornite EJB 2.0 hizo todo 10s posible para que hubiera el mayor parecido posible entre 10s dos lenguajes.

Algo que destacar sobre el argurnento FROM ( S p o r t E J B ) es que n o es la clase del EJB, ni su e j bname; es suesquema abstracto. Debe proporcionar una e t i q u e t a < a b s t r a c t - schema-name>

Beans de entidad y persistencia


(como anteriormente, antes de las etiquetas <cmp-f i e l d s > ) antes de poder escribir consultas

Q L EJB. (A titulo personal, nunca he podido obtener una respuesta clara del equipo EJB 2.0 a la
pregunta de por quk se introdujeron < a b s t r a c t - s c h e m a - n a m e s > cuando lo 6nico que hacen es una asociaci6n exacta a un nombre EJB. Mi conclusidn es que fue introducido para posibles evoluciones futuras.)
0

Si la clausula QL EJB se detuviera en este punto, el buscador obtendria todos 10s EJB contenidos en la tabla. Puesto que, obviamente, no es lo que queriamos, necesitamos refinar mas la solicitud y esto es lo que hace la clausula WHERE. Hace referencia a1 objeto o, uno de sus campos C M P (owne rName) y lo compara con el primer parametro ( ? 1)que ha sido pasado a1 mktodo Java f indByOwnerName ( ) (que es una cadena, como hemos especificado antes).

BMP y d t o d o s bwcador Continuando con nuestro ejemplo de equipo de deporte, kste es un ejemplo de implementaci6n de f i n d B y P r i m a r y K e y ( ) para la versi6n con persistencia gestionada por bean (recuerde que no existe equivalente para la versidn con persistencia gestionada por contenedor; afiada estos mktodos s61o a la versi6nBMPdesport~eamj ~a ~v~ a) .:
public S p o r t T e a m P K e j bFindByPrimaryKey ( SportTeamPK primaryKey) throws FinderException { Connection con = null; try I con = getConr~ection ( 1 ; Preparedstatement statement = con.prepareStatement ( "SELECT SPORT " + "FROM SPORTSTEAMS WHERE SPORT "AND NICKNAME = ? " ) ; s t a t e m e n t . s e t S t r i n g ( 1 , primaryKey.getSport()); s t a t e m e n t . s e t S t r i n q ( 2 , primaryKey.getNickName()); Resultset resultset = statement.executeQuery(); if ( ! resultset. next ( ) ) { throw new Obj ectNotFoundException ( ) ; 1 resultset. close ( ) ; statement.close t i ; return primaryKey; I catch (SQLException sqle) { t h r o w n e w E J B E x c e p t i o n ( s q 1 e ); 1 finally { try I if ( c o n ! = null) { con.close ( ) ;
I
)

"

catch

(SQLException s q l e ) 1 1

~ s t es e un ejemplo de implementaci6n de un buscador que tiene cero o mas resultados y devuelve una colecci6n:
p u b l i c Collection ejbFindByOwnerName(String o w n e r N a m e ) throws Fir~derException { Connectior~ con = null; try i con = getConr~ection ( ) ; Preparedstatement statement = / / Primary key info con.prepareStatement("SELECT SPORT, NICKNAME " t

Capitulo 16
"FROM SPORTSTEAMS WHERE OWNERNAME s t a t e r n e n t . s e t S t r i n g ( 1 , ownerNarne); R e s u l t s e t r e s u l t s e t = staternent.executeQuery();
=

' I ) ;

L i n k e d L i s t q l l e r y M a t c h e s = rlew L i n k e d L i s t ( ) ; while (resllltSet.nezt ( 1 1 { SportTearnPK p k = new SportTearnPK(resultSet.getString(l), r e s u l t s e t . g e t S t r i n g ( 2 )) ; queryMatchis.add(pk);

I
resultSet.close( ); statement.close(); r e t u r n queryMatzhes; c a t c h (SQLEszeption s q l e ) [ t h r o w new E J B E z c e p t i o n ( s q l e 1 ; finally { try i i f (car, != n u l l ) [ con. c l o s e ( ) ;

]
)

i
}

catch

(SQLException s q l e )

Tanto para la version C M P como para la version BMP de nuestro bean de equipo de deporte, debe completar la interfaz inicial como sigue:
S ~ , , r t T ? a r n findByPrirnaryKey(SportTearnPK s p o r t T e a m ) throws RernoteException, FinderException; C o l l e c t i o n f i n d B y O w n e r N a m e ( S t r i n g ownerName) throws RernoteException, FinderException; 1

Activation y pasivacion
Dos de las retrollamadas para beans de entidad son e j b A c t i v a t e ( ) y e jb P a s s i v a t e ( ) . Los beans de sesi6n tienen estas mismas retrollamadas pero sirven diferentes propbsitos. En realidad, para beans de sesi6n sin estado, no tienen ningun objetivo; estin ahi para que 10s beans de sesi6n con estado y sin estado puedan implementar la misma interfaz. Para beans de sesi6n con estado, indican a1 bean que esti a punto de ser guardado o restablecido de almacenamiento secundario, que ayuden a1 contenedor EJB a gestionar su equipo de trabajo. Los beans de entidad no tienen que ser guardados en almacenamiento secundario: por definition, ya existen en almacenamiento persistente. Si el contenedor no utiliza un bean de entidad, no necesita preocuparse por preservar su estado antes de liberar sus recursos. Para beans de entidad, e j b A c t i v a t e ( ) proporciona una notificacion que indica que la instancia de bean de entidad ha sido asociada a una identidad (una clave primaria) y ya esta preparada para que e j b L o a d ( ) sea cargado antes de la invocaci6n del mktodo de empresa. Se invocari un metodo e jb p a s s i v a t e ( ) coincidente para notificar que el bean de entidad estin siendo disociado de una entidad concreta anterior a la reutilizacion (con otra entidad o mktodos buscadores) o quizis antes de eliminar la referencia y convertirlo en susceptible de recolecci6n de residuos. El unico caso en el que el bean de entidad se encargaria de la informaci6n proporcionada por e j b A c t i v a t e ( ) y e j b p a s s i v a t e ( ) es a la hora de gestionar ciertos recursos que dependieran de la identidad de un bean. Por ejemplo, podria necesitar estas retrollamadas para abrir y cerrar conexiones de bases de datos. Fuera de este caso, la implementaci6n de estos mktodos puede quedar vacia. U n ejemplo de

Beans de entidad y persistencia


situaci6n en la que el bean de entidad podria necesitar un recurso asociado a una identidad concreta seria la posibilidad de tener una referencia remota a un objeto no Java cuyo estado necesitara ser sincronizado con el estado de un bean de entidad, como un objeto de empresa en un servidor de aplicaci6n de propiedad perteneciente a un vendedor de sistemas ERP. Si el recurso necesita asociarse a un identidad concreta, debe en realidad proveer la inicializaci6n de ese recursoene j b p o s t c r e a t e ( ) y e j b A c t i v a t e ( ) ,porque laentidadpuedellegaraasociarse conun identidad a travCs de cualquiera de estas rutas. Observe que necesitae j b P o s t C r e a t e ( ) en lugar de e j b C r e a t e ( ) ,porquee j b P o s t C r e a t e ( ) es el lugar donde la identidad se convierte en disponible. De un mod0 similar, debe utilizar e j b ~ a s s i v a t e ( ) y e j bRemove ( ) para la liberaci6n de recursos. Tambien es posible que el recurso no necesite ser asociado a una identidad concreta, sin0 que simplemente necesite estar disponible en general a cualquier identidad. Por ejemplo, puede tener una conexi6n a un sistema ERP de legado que puede utilizar para sincronizar datos para cualquier objeto. Puede utilizar 10s m~todosderetrollamadaset~ntity~ontext ( ) y u n s e t E n t i t y C o n t e x t ( ) paradesignary recuperar el recurso en este caso. ~ s t o son s 10s metodos para ambas versiones de nuestra implementaci6n de bean de deporte (localizados en 10s archivos S p o r t T e a m E J B para BMP y CMP):
public void ejbActivate ( public void

I
)

1
{ ]

ejbpassivate (

Con la adicion de estos metodos, la version CMP de la clase de implementicion esti completa. Quedan un par de metodos para el bean BMP.

El ciclo de vida completo


El siguiente diagrama resume la informaci6n sobre retrollamadas de contenedor para beans de entidad. En el estado reservado, se inicializa una instancia de entidad per0 n o se asocia a una identidad concreta. En otras palabras, no tiene una clave primaria concreta, ni representa el estado de una fila concreta en la base de datos. En este estado, s61o puede ser utilizado por metodos buscadores (que se aplican a beans de entidad en el agregado) o para metodos de empresa de inicio. En el estado listo, la instancia se asocia a una identidad particular y puede ser utilizada para metodos de empresa. El contenedor EJB puede crear una instancia de un bean de entidad y trasladarla a1 estado reservado o listo a su discrecion, invocando e j b L o a d ( ) y e j b S t o r e ( ) segun las reglas descritas anteriormente en este capitulo. En la prictica, un contenedor EJB s d o trasladari una entidad a1 estado listo cuando un cliente quiera utilizarla y mantendri esa entidad en el estado listo; la trasladari a1 estado reservado o destruiri el bean dependiendo de la estrategia de almacenamiento en memoria cache utilizado. Este es el diagrama:

Capitulo 16

lnlcio

argurnentos

Constructor sln mvocado


Final -

; unsetEnt~tyContext
I
L ~ '

1I

,
+
-

Estado resewado

1
ejbActlvate ej bPass~vate ejbRemove Estado l~sto v
V

ej bCreate

ejbPostCreate

t
A

Metodos de empresa

Reentrada
A diferencia de 10s beans de sesibn, que nunca son reentrables, un bean de entidad puede ser especificado como reentrable o n o reentrable. U n bean reentrable es aquel que permite una "retrollamada" (por ejemplo, un bean de entidad de Order invoca un bean de entidad de LineItem, que invoca entonces el bean Order). La llamada inicial a LineItem ha vuelto como retrollamada a Order. O t r o uso para beans reentrantes son beans recursivos, que se invocan a si mismos por cualquier motivo.
Si el bean Order de este ejemplo fuera especificado como reentrante, se permitiria la Ilamada. Si el bean Order fuera especificado como no reentrante, el contenedor EJB rechazaria la llamada y generaria una excepci6n j a v a . r m i . R e m o t e E x c e p t i o n (o j a v a x . ejb.EJBExceptionene~casodeunainterfaz~oca~). Muchos programadores estin acostumbrados a un estilo de programacih en el que 10s articulos secundarios (corno un articulo de linea) tienen una referencia a1 principal que 10s contiene (corno un pedido). Esto es ciertamente dtil en diversas situaciones y esti permitido. Sin embargo, la especificaci6n no recomienda (aunque no prohibe) convertir a 10s beans de entidad en reentrantes porque puede impedir que el contenedor guarde en cache una clase concreta de error (por ejemplo, el contenedor ya no podria indicar una contrasehal de un acceso concurrente por otro cliente).

Beans de entidad y persistencia


Si un bean es codificado como reentrante, el contenedor EJB no puede evitar que un cliente multi-hilo que opera en una unica transaccidn realice multiples llamadas a1 bean de entidad. Aunque 10s beans de entidad son diseiiados para ser de hilo unico, esto puede desembocar en una situacidn en la que dos (o mis) hilos de control operen simultineamente sobre una h i c a instancia de un bean de entidad. Este es el tip0 de error de sistema para el que se diseiio la tecnologia Enterprise JavaBeans. Gracias a ella, el programador de logica de empresa puede d e s p r e o c ~ ~ a r de s e este problems y, en parte, kste es tambikn el motivo por el que la especificaci6n sugiere a 10s programadores de bean que eviten 10s beans reentrantes.

Simplemente conlo apunte, en mi opinidn deberia haber hecho lo imposible por crear una situacidn en la que mtiltiples hilos de control accedieran a u n bean de entidad en la misma transaccidn. Por ejemplo, puesto que 10s beans de sesidn no pueden tener multiples hilos, no podria hacerlo si accediera a sus beans de entidad a travb de una fachada de bean de sesidn. En cualquier caso, yo no contradiria la especificacidn, que recomienda precaucidn a1 rescribir beans reentrantes. S e g h m i experiencia, la precaucidn en programacidn nunca es demasiada.
Si un bean es o no reentrante esti indicado en el descriptor de implementaci6n XML y se pareceri a uno de 10s siguientes:

<reentrant>False</reer~trant>

Ni nuestro C M P ni nuestro BMP son reentrables.

Completar el ejemplo del equipo de deporte


A1 considerar las diferencias entre beans de entidad con persistencia gestionada por contenedor y aquellos con persistencia gestionada por bean, hemos completado la interfaz inicial y gran parte de la clase de implementacidn para el ejemplo del equipo de deporte. Ademis, hemos proporcionado 10s descriptores de implementacidn completos para ambos ejemplos. Para poner a pmeba nuestros dos beans de deporte, necesitamos concluir las clases de implementacidn y proporcionar una interfaz remota y un cliente. Estos ejemplos han sido desarrollador en el servidor de apkaci6n WebLogic Server 6.1, por lo que tambikn le indicaremos quk necesita hacer para implementar aqui 10s beans. Comencemos examinando la interfaz remota. Es la misma para ambas versiones (CMP y BMP), except0 el nombre del paquete. El cliente no tiene que preocuparse por el mecanismo de persistencia utilizado por el EJB:
package sportBean.bmp;

import j avax.ejb.*; public interface SportTeam exter~ds EJBObject public void setOwnerName (Strinq dwr~erNarne) throws j ava. rml . RemoteExceptlor~; public String g e t O w n e r N a m e 0 throws java.rmi.RemoteException;
{

public void setFranchisePlayer(String playerName) throws java.rmi.RemoteException; public String getFranchisePlayer() throws java.rmi.RemoteExceptior~;

Capitulo 16
Por supuesto, necesitamos proporcionar mktodos c ~ r r e s ~ o n d i e n ten e s nuestra clase de implementaci6n, SportTeamEJB. Observe que s610 10s proveemos para la versi6n BMP de nuestro bean:
public void setOwnerName (Stririq ownerName) { this. ownerName = ownerName;

I
public Strinq qetOwnerName ( return ownerName; 1
)

public void setFranchisePlayer(Strinq playerName) this. franchisePlayer = playerName;

1
public String getFranchisePlayer ( return franchisePlayer;
)

I
La versi6n BMP utiliza un mktodo de utilidad para recuperar la conexi6n:
private C o n n e c t i ~ r ,getConnection ( ) ( try i Context initial = new InitialContext ( ) ; DataSource datasource = ( D a t a S o u r c e ) initial. lookup("java:comp/er~v/jdbc/sportsJDBC") ; ( ) ; return datasource. qetConnectior~ 1 catch ( javax.naminq.NamingException n e ) { ne.printStackTrace( ) ; t h r o w r ~ e w EJBException ( n e ); I catch (java .sql .SQLException sqle) [ sqle.printStackTrace0; throw n e w EJBExceptionisqle);

I I
Ahora tambikn esti completo. Finalmente, proporcionemos un sencillo cliente para probar nuestros beans. Las iinicas diferencias en 10s clientes serin 10s nombres de paquete (por supuesto, incluso esto n o es necesario), las propiedades para inicializar el context0 JNDI y la biisqueda de la interfaz inicial. El cliente CMP ~ s t es a la versi6n para CMP:
package sportBean. cmp; import import import import import import import j ava. rmi . RemoteException; javax.ejb.+; *; j avax. namin~j. javax. rmi. PortableRemoteObject; java.util.Properties; java.util.Collection; java.util.Iterator;
{

public class Testclient

public static void main(Strinq[] args) { try i Properties prop = new Properties ( ) ; prop. setproperty (Context.INITIAL CONTEXT FACTORY, z "weblogic. jndi . W L I n i t i a l C o r ~ t e x t F a c t o r y " ); prop.setProperty(Cor1test. PROVIDER-URL, "t3://localhost:7001")

Beans de entidad y persistencia


InitialContext initial = new InitialContext (prop) ; Object homeObj ect = initial. lookup ("CMPSportsBean") ; SportTeamHome home = (SportTeamHorne) PortableRemoteObject.r~arrow(homeObject, SportTeamHome.class);
/*

* Crear una fila en la base de datos * (la eliminaremos a1 final de este ejemplo) */
System.out .println ("Creatir~ga row") ; home.create ("basketball", "Kings", "Joe Maloof", "Jason Williams") ;

System.out.prir~tlr~("Lcokir~g up by primary key..."); SportTeam team = home. findByPrimaryKey (r~ewSportTeamPK("basketball", "Kings") ) ; System.c~ut .println ("Current frartchise player: " ) ; System.out .println ( t e a m . q e t F r a r i c h i s e P 1 a y e r ) ) ; System.out .println ("Lccckir~g up by owner.. . " ) ; Collection collection = home. findByOwnerName ( "Joe Maloof" ) ; if ( 0 == collection.size() 1 { System. out .println ( " Fcur~d no such owner") ; 1 else { Iterator iter = collection. iterator ( ) ; while (iter.hasNext ( ) ) { Object objRef2 = iter.next ( ) ; SportTeam teamRef2 = (SportTeam) PortableRemoteObj ect .r~arrow(obj Ref2, SportTeam.class); System.out .println ("Owner rjame:

"

teamRef2.getOwnerName

( ) ) ;

I I
/ / Esto provocar6 que el equipo sea eliminado de la base de datos team.remove( ) ; catch ( javax. ejb.RemoveExceptiunr r e ) { re.printStackTrace(); catch (RemoteException r e ) { re.prir,tStackTrace ( ) ; catch (NamingException n e ) { ne .printStackTrace ( ) ; catch (CreateException c e ) { ce. printStackTrace ( ) ; catch ( javax.ejb. FinderException fe) { fe.printStackTrace ( ) ;

]
)

] ]

El client8 BMP
La version para BMP es bastante similar:
package import import import import sportBeai-1.bmp; j ava. rmi. RemoteException; javax.ej b. * ; j avaz. naming. * ; j avax. rmi. PortableRemoteObj ect;

Capitulo 16
import java.util.Frnperties; i m p ~ ~ rj ta v a . u t i 1 . C ~ l l e c t i o n ; import java.util.Iterator; p u b l i c class TestClient
{

pi~blic static vc2id main(String[] args) { try I Properties prop = rtew Properties ( ) ; p r o p . s e t p r o p e r t y ( C o r ~ t e x. tI N I T I A L C O N T E X T FACTORY,
"webloqic.jndi.WLInitia1Cory");

prop.setPropert.y ( C o r ~ t e x tEROVIDER . URL, Ir~itialCorltext initial O b j e c t h o m e o b j ect


=

"t3://lucalhost:7001")

riew IrtitialContext (pr,~,pj;

ir~itial .lookup i "BMPSportsBeanW) ;

SportTeamHome home = ( S p ~ r t T e a m H o m e )PartableRemnteOb]ect.na~row(homeObl~ct, SportTeamHnme.class1; S p o r t T e a m team


=

home. creat e ("basketball", "Kings", "Jason Williams");

"Joe Malfiof",

System.out .println ("Currer~t frarlchise player: " team.getFranchisePlayer()); team.setFranchisePlayer("Cedric Beust"); System.out . p r i n t l n ("New franchise player: " t team.getFranchiseP1ayer ( ) ) ;

Collezti~,n c o l l e c t i o n = home. findByOwnerName ( " J o e M a l o o f " ) ; Iterator iter = c o l l e c t i o n . i t e r a t o r ( ) ; if ( ! i t e r . h a s N e x t ( ) ) { S y s t e m . o u t .println ( " F n u n d n o s u c h o w n e r . " ) ; ) else [ Object o b j R e f 2 = iter.next ( ) ; SportTeam teamRef2 = (SportTeam) PortableRemoteObject.narrow(objRef2, Sp~rtTeam.class) ; S y s t e m . o u t .printlr~("Owr~er name:

"

teamRef2.getOwnerName

) ;

I
}

] ]

team.remove ( 1 ; catch (RemoteEception re) { re.printStackTracei ) ; c a t c h (Namir~gException n e ) { r i e . p r i n t S t a c k T r a c e( 1 ; catch ( C r e a t e E x c e p t i ~ n c e ) { ce.printStackTrace ( ) ; c a t c h ( j a v a x .ejb.RemoveExce~.tion r e ) { re.printStackTrace ( ) ; c a t c h ( j a v a x .ejb. Fir~derException f e ) { fe.printStackTrace ( 1 ;

1 Como estamos implementando nuestros EJB en WebLogic 6.1, necesitamos definir dos descriptores de implementation adicionales:weblogic- e j b - j a r .x m l especificainformaci6n adicional especificade

B70

Beans de entidad y persistencia


WebLogic, que ya ha visto, y uno nuevo, que puede tener un nombre de archivo arbitrario (lo llamaremos w e b l o g i c - c m p .xml). Este descriptor s61o tiene sentido si tiene beans de entidad CMP. Su contenido es bastante auto-explicative, como veri a continuacidn: este descriptor especifica cdmo 10s campos Java C M P estin asociados a las columnas de la base de datos, qu6 tabla utilizari, etc. ~ s t o son s 10s dos descriptores de implernentaci611, empezando p o r w e b l o g i c - e j b- j a r xml (observe que este archivo debe contener el nombre del descriptor C M P de mod0 que WebLogic sepa qu6 archivo buscar):
<!

DOCTYPE weblogic-ej b-j ar PUBLIC '-//BEA Systems, Irjc.//DTD WebLogic 6.0.0 EJB//EN1 'http://~~w.bea.com/servers/wls6OO/dtd/weblogic-ejb-jar.dtd'>

<weblogic-e j b-j ar> <weblogic-enterprise-bean> <ej b - n a m e > C M P S p o r t s B e a r ~ < ' / e jb-name> <entity-descriptor> <persistence> <persistence-type> -:type-identifier>WebLogic CMP RDBMS</type-identifier> <type-version>6. O</type-versior~> <type-storage>META-INF/web1ogic-cmpFxm1</type-stora:~e> </persistence-type> <persistence-use> <type-identifier>WebLdqic CMP RDBMS</type-identifier> <type-version>b.O</type-version> </persisterjce-use> </persistence> </entity-descriptor>

< j r t d i - n a m e > B M P S p o r t s B e a n < / j ndi-name>

c/wehlogic-enterprise-bear)> </weblogic-ej b-j ar>

Observe que la seccidn correspondiente a nuestro bean C M P es mis extensa que la de nuestro bean BMP. E s t e e s w e b l o g i c - c m p . xrnl:
< ! DOCTYPE

wehlogic-rdbms-j ar PUBLIC '-//BEA Systems, Inc.//D'rD WebLogic 6.0.0 EJB RDBMS Persistence//ENf 'http://www.bea.com/servers/w1s6OO/dtd/ weblogic-rdbms20-persister~ce-6UU.dtd'>

Capitulo 16

<field-map> <cmP,-f i e l d > s p o r t < / c m p - f i e l d i <dbms-c~lun1n>SPORT</dOms-ci'1umr1> c/ f i e l d - m a p i \field-mapi

<cmp-field>ni.ckName</cmp-field,
<dbm~-columr~>NICKNAI4E</dbms-~~lumr~>

</ f ield-map>
<field-map>

ccrnp-field>owr~erNarne</cmp-field> d b r n s - c o l umn>OWNERNAME</dbms-col!~mr,>
</f ield-nap> <field-mapi <cmp-f i e l d > f r a n c h i s e P l a y e ~ - < / c m p , - f ield>

<dbm:-column>FRANCHISEPLAYER</dbms-column>
</field-map>

C o m o revision, 10s EJB consisten en 10s siguentes archivos:


sportBean/ cmp/ SportTeam. c l a s s S ~ ' c 1 r t T e a m E J B,.z l a s c SpartTearnHome.class S p o r t T t a m P K . cia-r bm~ / Sp~z~rtTtam c l. a . 5 ~ SportTeamEJB. c l a s s SportTeamHomt.clas~ S ~ ' i ' r t T e a m P Kc . lass k1ETA-INF/ ejt'-jar.xm1 w e b l o g i c - e j b - j a r .xml web1 o g i c - c m r l . x m l

Configurar WebLogic 6.1 para nuestros EJB


El ultimo paso antes de poder implementar nuestros EJB es configurar las fuentes de datos en WebLogic 6.1. Esto se realiza en el archivo c o n f i g .x m l , que puede editar a travis de la Consola WebLogic (muy facil de hacer), o editando el archivo directamente de forma manual (lo encontrari en el directorio b e a \ w l s e r v e r 6 . l \ c o n f i g \ m y d o m a i n ) . Elfragmento d e c o n f i g .x m l relevantees:

Beans de entidad y persistencia

Fijese en que tendri que adaptar las propiedades de la reserva de conexiones para definir el host de su base de datos, el driver JDBC que debe utilizar, etc. Remitase a la documentacidn del servidor para detalles sobre el procedimiento. Si esti ariadiendo las reservas de conexiones y fuentes de datos desde la consola, ya no tiene que hacer nada mis: WebLogic Server creari automhticamente 10s recursos. Si ha editado su config.xml rnanualmente, serh necesario que se detenga y reinicie WebLogic Server para que estos cambios tengan efecto. Para crear su EJB, simplemente Cree un archivo JAR que contenga la jerarquia anterior, despuks cdpiela en el directorio applicat ions/ de su servidor WebLogic. Una vez funcionando el servidor y el archivo JAR implementado, puede entonces invocar ambos clientes:

Relaciones
Una de las preguntas mas comunes sobre beans de entidad hace referencia a cdmo irnplementar relaciones entre ellos. La buena noticia es que las relaciones son una parte integrante de la especificacidn EJB 2.0, lo que significa que el contenedor se encargarh de todos 10s detalles de implementaci6n de nivel inferior. La rnda noticia es que necesita familiarizarse con algunas nociones antes de poder explotarlas a1 miximo.

Crear interfaces locales


Lo primero que necesita saber es que 10s beans s61o pueden ser conectados con una relacidn CMP a travks de sus interfaces locales. Por lo tanto, va a necesitar crear una interfaz Local para cada uno de esos beans

(10s beans conectados por una relacion deben estar en la rnisma unidad de irnplementacibn: el rnismo archivo JAR o el rnismo archivo EAR). Crear una interfaz local para un bean es bastante sencillo; conlleva 10s siguientes pasos:

O Crear una nueva interfaz que amplie j a v a x .e j b .EJBLocalHome. Esta clase es similar a la interfaz inicial rernota excepto en que sus metodos no esti autorizados para generar excepciones RemoteException. O Crear una nueva interfaz que arnplie j a v a x .e jb .E J B L o c a l O b j e c t s . Cjase es similar a la interfaz de objeto remoto excepto en que sus rnetodos no pueden generar excepciones RemoteException.
0 La interfaz inicial local puede tener 10s mismo rnetodos que una interfaz inicial remota, crear, buscadores, etc. la h i c a diferencia es que 10s objetos que devuelve son E JBLocalOb j e c t , no

remotos.
O

Ariadir elementos<local-home> y < l o c a l > a su descriptor de irnplementacione j b - j a r . xml, en lugar de <home> y < r e m o t e > . Deben hacer referencia alas clases anteriores.

Ademas de estos Dasos. tendria que modificar algunos descri~tores de im~lementacibn adicionales " dependiendo del servidor de aplicaci6n que utilice, corno otorgar un nornbre JNDI a la interfaz inicial local, asociar referencias locales a EJB, etc. El ejernplo de factoria anterior explica 10s pasos necesarios para WebLogic 6.1.
,

Definir las relaciones


Ahora que ya tiene interfaces locales, sus beans pueden participar en una relaci6n. Suponga que tiene dos EJB: Producto y Pedido, y que un Pedido hace referencia a un Producto. Primero, necesitamos explicar algunas caracteristicas de la relaci6n:

O Cardinalidad. Una relaci6n puede ser uno-uno, uno-varios o varios-varios. Arbitrariamente, elijamos uno-uno: un pedido esti relacionado con un solo producto. Obviarnente, un pedido podria contener varios productos. Birecc5n,
-

La relaci6n puede ser unidireccional o bidireccional. De nuevo, se trata de su decisi6n. Obviamente, cuando tenernos un pedido, queremos alcanzar el producto. iQuiere que lo contrario tarnbien sea posible? En ese caso, la relacion sera bidireccional; si no es asi, seri unidireccional. Optemos por una relaci6n unidireccional.
0

Campos CMR. Necesitarnos un carnpo en el Pedido EJB que haga referencia a1 producto, campo denominado CMR (campo de relaci6n gestionado por contenedor) a1 que llarnarernos p r o d u c t o r d e r e d . Puesto que la relacidn es unidireccional, no necesitamos otro carnpo CMR, per0 si fuera el caso, necesitariamos definir un campo simetrico en el Producto EJB (a1 que llamariarnos o r d e r ) .

Ahora ya tenemos toda la informaci6n que necesitamos para definir la relaci6n en el descriptor de irnplernentacibn e j b - j a r .xml. U n Gltirno detalle antes de lo mostremos: una relacion se define por dos roles, definiendo cada rol la mitad de la relacion. En el siguiente ejemplo, observari que la Gnica diferencia entre 10s roles es que el segundo (Producto a Pedido) no tiene un carnpo CMR, por el motivo citado anteriormente. Asi es c6rno definiriamos nuestra relacibn entre O r d e r E J B y P r o d u c t E J B :

Beans de entidad y persistencia

En lo referente a Java, un campo C M R no se diferencia de un campo CMP: hay que declarar configuradores abstractos y el contenedor generari la implementaci6n por nosotros:
abstract public class OrderEJB implemer~ts EntityBean
//

...

//

Campo CMR abstract public LocalProduct getProductOrdered(); abstract publls void setProductOrdered ( LocalProduct pi

Observe que el tipo de campo CMRes LocalProduct,no Product,como establece la especificacion.

Completar nuestra aplicacion de fabricacion


Empezamos a rnodelar una instalaci6n de fabricacibn en el ultimo capitulo. En el c6digo de ese capitulo, referenciamos dos beans de entidad, aunque aplazamos un tratamiento completo de esos dos beans, Order y Product,hasta este capitulo. Como hemos elegido persistencia gestionada por contenedor, la implementaci6n de estas dos clases es bastante sencilla. Observe que la asociaci6n exacta de estas clases a tablas de base de datos dependeri de la implementaci6n de la asociaci6n objeto/relacional de su contenedor EJB para persistencia gestionada por contenedor. En el mejor de 10s casos, tendri gran flexibilidad, la suficiente para emparejar sus beans con tablas preexistentes utilizadas para otros sistemas. Para un contenedor adecuado, el peor de 10s casos es probablemente que 10s objetos dependientes del producto se codifiquen en una unica columna de tabla. (La mayoria de 10s contenedores manejarin la relaci6n uno-a-uno entre pedido y producto almacenando la clave del producto en una columna de la tabla de pedido, comportamiento que probablemente desee.) Una funci6n opcional que puede tener su contenedor es lade crear automiticarnente tablas que utilizari para la persistencia C M P de un bean de entidad. Si aprovecha esta funcibn, obtendri automiticamente una

Capitulo 16
estructura de base de datos apropiada para las capacidades de su contenedor. Tambikn tendri el problema de la configuraci6n de asociaciones objetos/relacionales. Por supuesto, esta funci6n n o se utilizaria si estuviera trabajando con un disefio de base de datos relational existente.

Empecemos con las interfaces para el bean Pedido.

La interfaz inicial del Bean Pedido


Los rnktodos c r e a t e ( ) y 10s mktodos buscadores son declarados en la interfaz inicial:
package import import import import import public Order factory.order; j avax. e j b . + ; j a v a . rmi . R e m o t e E x c e p t i o n ;

factory.product.Loca1Product;
java.util.Date; j ava.uti1 .Collection; interface OrderHorne extends EJBHome
{

create ( i n t ~ a l e s D i \ ~ l s i o nl , n t orderNumber, LocalProduct productordered, Date d a t e D u e ) throws RernoteException, c r e a t e ( i n t s a l e s D i v i s i o n , i n t orderNumber, String productordered, Date ,dateDue) throws RemoteException,

CreateException;

Order

CreateExceptior~;

Order

firldByPrimaryKey(0rderPK o r d e r )
f indOpenOrders ( ) throws

throws

RernoteException, FinderException; FinderException;

Collection Collection

RernoteException,

findUncompletedOrders( )throws

RemoteEzception, FinderException;

1
Los mktodos buscadores son especificados en Q L EJB. Aqui tenemos dos:
<query> <query-method> <method-name>f i n d O p e r ~ O r d e r s < / m e t h o d - r i a m e > <method-pa rams> </method-params> </query-method> <ejb-qli < ! [CDATA[SELECT OBJECT ( 0 ) F R O M O r d e r s AS o WHERE ( o . i n t e r n a l S t a t u s = '0' O R o . i n t e r n a l S t a t u s = 'm' ) ] ] > </ejb-ql> </query> <query> 'query-methodi < m e t h o d - n a m e > f indUncompletedOrders</met.hod-name> <method-params> </method-params> </query-method>

Beans de entidad y persistencia


<ejb-ql> < ! [CDATA[SELECT OBJECTlo) F R O M O r d e r s AS o WHERE ( 0 . i r l t e r n a i s t a t u s = ' 0 ' O R o . i n t e r n a l S t a t u s = 'rn' ) 1 1 > </ejb-ql> </query>

La interfaz remota del bean Pedido ~ s t o son s 10s mktodos de empresa para el pedido de la interfaz remota. Son bastante auto-explicativos:
package import import import imp,jrt public factory.order; j a v a x . e j b . +;

java.rmi.RernoteEzception;
java . u t i l . Date; factory.product. Product; irlterface int int Order e x t e r ~ d s EJBObject

public public piubiic public public

g e t S a l e s D i v i s i o n ( ) throws getOrderNurnber( ) throws

RemoteException;

RemoteException; throws RemnteException;

Product String void

getproductordered ( ) getstatus ( ) throws

RemoteException;

cancelOrder ( )throws RemoteException,

OrderNotCancelableException;
public public public void void Date beginManufacture ( ) throws RemoteExceptlon; RernoteExceptiort;

cornpleteMar~ufacture ( ) getDateDue ( ) throws

throws

RemoteException;

La clase de implementacion del bean Pedido


El bean Pedido tiene cinco propiedades de estado. Una de kstas es una referencia a otro bean de entidad (el producto). Esta relaci6n es bastante intuitiva: un pedido es para un producto. Por supuesto, en una aplicacidn real, un pedido probablemente tendria una lista de articulos; cada uno de esos articulos probablemente tendria un producto y una cantidad, asi corno otro tip0 de inforrnacidn. Pero esto es suficiente para comprender el concepto:
package import import import import i mpo r t import import import public factory.order;

ja v a x . e l b .

;
+

j a v a x . naming. ; j a v a . rrnl. R e m o t e E x c e p t i o r ~ ; f actory.product LocalProduct;

factory.product.Product; factory.product.ProductLoca1Home; factory.product.ProductHomt;


java.util.Date; abstract class OrderEJB irnplemertts EntityBearr
[

// Propiedades private s t a t i c

final

String

OPENpSTATUS

"0";

Capitulo 16
private private private private abstract abstract abstract abstract abstract abstract abstract abstract abstract abstract private static static stat-ic static public public public pub1 i c public public public public public public String final final final final S t r i r ~ g DEFAULT STATUS = OPEN STATUS; S t r i n g CANCELED STATUS = " c " ; S t r i n g I N PROCESS STATUS = "m"; S t r i n g COMPLETED STATUS = " f " ;

i n t getOrderNumber ( ) ; void setOrderNumber(int orderNumber); LocalProduct getProductOrdered(); void setProductOrdered ( LocalProduct

p);

int getSalesDivision(); void setSalesDivision ( i n t salesDivisionj ; Date void getDateDue ( ) ; setDateDue (Date d a t e ) ;

String get1nternalStatus ( j ; v o i d s e t I n t e r n a l S t a t u s ( S t r i n g s ); status;

//

la

clase

continfia

Observe que hemos definido cinco variables estiticas privadas para utilizar en esta implementaci6n. La especificacion permite variables estiticas en EJB, per0 deben ser de s6l0 lectura. Para poner esto en prictica, las declaramos f i n a l . Asimismo, fijese en 10s pares de accesores, uno para cada campo CMP. Como se establece en la especificaci6n EJB 2.0, son declaradas abstractas y el contenedor las generari. Las funciones de retrollamada en O r d e r E J B estin vacias; podemos dejar todo en manos del contenedor:
public public public public public public public void void void void void void void ejbLoad(j ejbStore()

[I
[

1
{

ejbActivate i) ejbfassivate ( ) ejbRemove(


{

1
{ )

1
[ ]

setEntityCor1text (EntityContext c t x ) u n s e t E r ~ t i t y C o n t e x (t )
{

El bean Pedido proporciona dos versiones de su metodo c r e a t e ( ) . Aunque adoptan la misma informacibn, una versi6n acepta el nombre de cadena de un producto y la otra acepta una referencia remota. La versi6n que toma el nombre de cadena utiliza un mitodo de ayuda para convertirlo en un producto real. Si el nombre n o se corresponde con un producto, se genera una excepci6n CreateException. Observe que, para inicializar nuestro bean, tenemos que utilizar 10s configuradores C M P (no tenemos acceso a campos que representen campos CMP). Hemos visto esta parte anteriormente. La h i c a adici6n es que el producto solicitado esticonfigurado e n e j b P o s t C r e a t e ( ) ,n o e j b C r e a t e ( ) . El motivo es que este campo no es un campo persistente gestionado por contenedor, sino un campo de relaci6n gestionado por contenedor (campo CMR). Lo que lo diferencia es que el bean relacionado podria no haber sido creado todavia en el momento de e j b C r e a t e ( ) , por lo que podria n o tener todavia una clave primaria. Por otro lado, el contenedor garantiza que ocurriri asi en e j b C r e a t e ( ) , por lo que INSERTAR su valor en la base de datos puede suceder:

Beans de entidad y persistencia


//
Metodos d e c i c l o d e v i d a y d e s i s t e m a p u b l i c OrderPK e j b C r e a t e ( i n t s a l e s D i v i s i o n , i n t orderNumber, LocalProduct productordered, Date dateDue) throws CreateException s e t S a l e s D i v i s i o n ( s a l e s D i v i s i o r ~;)

setOrderNumber(orderNumber);
setDateDueidateDue); setIrlterr~alStatus (DEFAULT STATUS) ; status
=

DEFAULT STATUS;

r e t u r r ~n u l l ;

//

for

container-managed

persistence

I
public void e j b P o s t C r e a t e ( i n t s a l e s D i v i s i o n , i n t orderNumber, LocalProduct pro';luctOrdered, Date dateDue)
{

setProductOrdered(product0rdered);

I
public e j b c r e a t e ( i n t s a l e s D i v i s i o n , i n t orderNumber, S t r i n g product, Date d a t e D u e ) throws C r e a t e E x c e p t i o n s e t S a l e s D i v i s i o n ( s a l e s D i v i s i o r t ); OrderPK

setOrderNumber(orderNumber);
s e t D a t e D u e ( d a t e D u e ); s e t I n t e r n a l S t a t u s (DEFAIJLT STATUS) ; s t a t u s = DEFAULT STATUS; return null;

//

for

container-managed

persisterlce

I
public void e jbPostCreate ( i n t s a l e s D i v i s i o n , i n t orderNumber, String p r o d u c t , D a t e d a t e D u e ) {

/ / E l p r o d u c t 0 s o l i c i t a d o d e b e c o n f i y u r a r s e e n e j b P o s t C r e a t e ya q u e e s / / p a r t e d e una r e l a c i 6 n uno-uno
try i ProductLocalHome productHome = g e t P r o d u c t H o m e ( ) ; L o c a l P r o d u c t p = productHome.findByPrimaryKey(product); setProductOrdered(p); I catch (RemoteException r e ) [ re.printStackTrace0; t h r o w new E J B E x c e p t i o n ( r e ) ; ) catch (FinderException f e ) [ fe.printStackTrace0; t h r o w new C r e a t e E x c e p t i o n ( " P r o d u c t d o e s n o t e x i s t " ) ;

I
I
//
Ayudantes de implemer1taci6n

p r i v a t e ProductLocalHome getProductHome( ) { try 1 I n i t i a l C o n t e x t i n i t i a l = new I n i t i a l C o n t e x t ( ) ; P r o d u c t H o m e home = ( P r o d u c t L o c a l H o m e ) javax.rmi.PortableRemote0bject

.r~arrow(ir~itial.lookup("java:~omp/er~v/ejb/LocalProduct"), ProductLocalHome.class);
}

r e t u r n home; c a t c h (NamirtgException n e ) { ne.printStackTrace ( ) ; t h r o w new E J B E x c e p t i o n ( n e ) ;

Capitulo 16

Los metodos c r e a t e ( ) deben tener al menos informaci6n suficiente para especificar la clave primaria de un nueva entidad. En la prictica, normalmente tendrin mis. Hay dos posibles patrones para inicializar una nueva instancia con un conjunto de datos:
CI
0

Invocar el mktodo c r e a t e ( ) con ese conjunto de datos Invocar el metodo c r e a t e ( ) y despuis invocar mCtodos de actualizaci6n sobre la instancia Si utiliza el segundo metodo, debe asegurarse de que las llamadas de metodo de actualizacibn tienen todas lugar en la misma transacci6n que la llamada a create ( ) De n o ser asi, si algo ocurre entre su llamada create ( ) y las actualizaciones (como que su cliente falle), su base de datos puede quedar con una entidad esparcida a medio inicializar.

La clase de claw primaria del bean Pedido


La clave para el pedido es una combination de la divisi6n de ventas y el nljmero del pedido, ya que cada divisi6n de ventas tiene su propio sistema de asignaci6n de nljmeros de pedido, y 10s dos sistemas asignarian pedido pedidos contradictorios. Recuerde que cada clave primaria debe ser exclusiva. ~ s t es a la clave primaria para el bean Pedido:
package import public fqctory.order; java.io.Serializabie; class 0rde~.PK implements Serializatie
[

public public

~ n s talesDivisi,>n; i n t orderNurnber; obligatorin

/ / C o n s t r u c t o r vaci,, p u b l l c Ord?rPK! ) { 1

/ / C , , r t s t r u c t o r ;le c o r i v e n i e r r c i a p u b l i c OrderPK! i n t s a l e s D i v i s l o n , i n t this.salesDivisior1 = salesDivision; t h i s . orderNumber = orderNurnber;

orderNurnber)

I public i n t hashcode( return (salesDivision


1

<< 8

orderNurnber;

public boolean equals(0bject o t h e r ) { i f ( ( o t h e r == n u l l ) I 1 ! ( o t h e r i n s t a n c e o f return false;

OrderPK) )

OrderPK ritherPK return

(OrderPK) o t h e r ;

vision) ( s a l e s D i v i s i o n == o t h e r P K . s a l e s D ~ && ( o r d e r N u r n b e r == o t h e r P K . o r d e r N u r n b e r ) ;

I I

Beans de entidad y persistencia


Los campos de estado p ~ b l i c o ( s a l e s D i v i s i o n y o r d e r N u m b e r ) deben ser nombrados exactamente igual y deben tener el mismo tip0 que 10s campos c ~ r r e s ~ o n d i e n t del e s bean. Algo que debemos destacar es que el estado del pedido debe ser almacenado e n una h i c a letra e n la base de datos y e n el estado cache del bean de pedido. Sin embargo, el cliente espera obtener una cadena legible cuando pregunte por el estado. H e m o s definido estas cadenas en una clase externa para mayor sencillez, aunque el mejor enfoque sea probablemente cargarlos desde un recurso (para contribuir a la internacionalizaci6n, p o r ejemplo):

public class public s t a public s t a p ~ b l i cs t a ~ ) u b l i cs t a

t t t t

StatusStrings [ i c firla1 S t r i r ~ ic flnal String i c firla: Strirq Lq i c f i r t a l S ~i r

jOPEN = " o p e n " ; CANCELED = " c a r , c e l e J " ; I N PROCESS = " i n ~ L I ~ c ' B F . ~ " ; COMPLETED = " c o m p 1 e t i : d " ;

La letra almacenada e n la base de datos se denomina i n t e r n a l s t a t u s (y tiene su propio campo C M P ) per0 confiamos e n que nuestro cliente utilice g e t S t a t u s ( ) para obtener la cadena legible. Traducimos el estado cuando el cliente lo solicita e n el metodo g e t s t a t u s ( ) . Podriamos guardar e n cache el estado e n forma legible e n una variable transitoria (y haber trabajado con el e n esa forma en la 16gica de empresa) ariadiendo Iogica e n e j b L o a d ( ) para traducirla desde su formato de base de datos. Entonces, en e j b s t o r e ( ) , podriamos traducirlo e n la forma de base de datos y guardarlo e n un campo n o transitorio gestionado p o r contenedor. E s t o parece mucho trabajo para un valor tan pequefio. E n otros casos m6s complicados, este podria ser el proceso adecuado.

La excepcion OrderNotCancelableException
La e x c e p c i 6 n 0 r d e r ~ o t ~ a n c e l a b l e ~ x c e p tgenerada ion desde el r n C t o d o c a n c e 1 0 r d e r ( ) es una clase singular que ya hemos analizado brevemente e n el capitulo anterior. Se define del siguiente modo:
F acl.age
public factory. order; class

OrderNotCancelableExceptiur

extends

Exception

El bean Producto
El bean P r o d u c t o tiene tres propiedades de estado. D o s son cadenas: producto (que es la clave) y nombre (que es el nombre legible del producto), y el tercero es una lista de instrucciones de redireccionamiento. Las instrucciones son 10s pasos p o r lo que debe pasar el producto para ser creado. U n a instrucci6n de redireccionamiento se define asi:

import

j ava. io. Serialixable;

public class F!.~utir~qIr~structio im n plemerlts ~ ) u b l i ci n t s e q l J e n c e ; public Strirlg i r i s t ~ u c t i o n ; public RoutinqInetructior~(){ ]

Serializable,

Comparable

p u b l i c RoutingInstruction [ i n t sequence, t h i s . sequence = sequence; t h i s . instructiort = instruction; 1

String

irlstructior~) {

public i n t compareTo(0bject o ) j R o u t i n g I r ~ s t r u c t i o r , r i = ( R o u t i r ~ g I r ~ s t r u c t i o no); i f (sequence < ri. sequence) [ r e t u r n -1; 1 e l s e i f ( s e q u e n c e == r i . s e q u e n c e ) [ r e t u r n 0; j else { r e t u r r i 1;

Observe que se podria rnodelar corno un conjunto de beans de entidad relacionados. iPor quk hernos elegido hacer de las instrucciones de redireccionarniento un atributo?
0 El ciclo de vida de una

instruction de redireccionarniento esti cornpletarnente controlado por el producto en el que esti contenida. Una instrucci6n se crea para un producto concreto y debe ser elirninada si se elirnina el producto correspondiente.
Ninguna entidad distinta del producto se vinculari a esta instruccion de redireccionarniento independienternente. Si una "estaci6n de trabajo" necesitara tener una referencia a todos sus pasos de redireccionarniento asociados, rnereceria la pena hacer de la instruccih un objeto entidad de prirnera clase para apoyar esta asociaci6n.

0 Se trata de un objeto ligero y sufriria la sobrecarga de ser una entidad de prirnera clase.

La interfaz inicial del bean Producto


package import import import public factory.product; java.uti1 .Collection; j a v a x . e j b . +;

java.rrni.RemoteExceptior1;
interface ProductHnrne extends EJBHome
{

Product

c r e a t e ( S t r i n g p r o d u c t , S t r i n g name, C o l l e c t i o n r o u t i r ~ g I n s t r u c t i o r ~ s t)h r o w s

RemoteException, CreateException;

ProductPK

findByPrimaryKeyiStrir~g p r o d u c t )

throws

RemoteExceptiort, FinderException;

La interfaz inicial local del bean Producto


pachage import import import public factory.product; java. u t i l . Collection; j a v a x . e j b . *; j ava. r m i . RemoteException; interface ProductLocalHome e x t e r ~ d s EJBLocalHome
{

LocalPro,duct

c r e a t e (Strir1,g p r o d u c t , S t r i r l g name, Cnllection routirqInstruct ions)

throws CreateException;

Beans de entidad y persistencia

LocalProduct
1

firidByPrimaryKey(String p r o d u c t )

throws

FinderException;

La interfaz remota del bean Producto

Los mitodos de empresa del bean de entidad del producto se definen en la interfaz remota del siguiente rnodo:
package import import factory.product; j avax. e j b . +; j a v a . rmi. RernoteExceptior~;

p u b l i c i n t e r f a c e P r o d u c t e x t e r J d s EJBObject { p u b l i c S t r i n g g e t p r o d u c t ( ) throws RernoteException; public public String void getName() throws RernoteExceptior~; thrriws RernoteExceptlon;

s e t N a r n e ( S t r 1 n g name)

/ / Metodns d e ernpresa public void addRoutir~gInstructio( r~ i r ~ ts e q u e n c e , S t r i n g i n s t r u c t i o n ) throws


public

RemriteException;

sequer~ce) v o i d deleteRoutir~gIr~structior~(ir~t t h r o w s N o S u c h R o u t i r ~ g E x c e p t i o r ~ ,R e r n o t e E x c e p t i o n ; Collectlori

public

g e t R o u t i r ~ g I r ~ s t r u c t i o( r) ~ s
t h r o w s RernoteEzception;

public

void

setRoutingInstructior~s (Collectior1 c ) t h r o w s RernoteException;

public

(s R ~ u t i r ~ g I n s t r u c t i[ o I r~ v ~ i dr e p l a c e R o u t i r ~ g I n s t r u c t i o r ~ r i e w R o u t i r ~ g I r ~rs~ t uctior~s) t h r o w s RernoteException;

La clam de implementation del bean Producto

~ s t es e el estado de nuestro bean de entidad del producto:


package import import import import import public factory.product; javax. ejb.*; j ava. u t i l .List; j ava.uti1 .LinkedList; java. u t i l .Arrays; java. u t i l . Iterator; abstract class ProductEJB irnplernerlts ErltityBean
{

public public

abstract abstract public public public public

Collectiori getRI ( 1 ; void setRIlCollection

c);

abstract abstract abstract abstract

String getproduct ( ) ; void setProduct(3tring p ) ; S t r i n g getNarne ( ) ; v o i d setNarne ( S t r i n g name) ;

Capitulo 16
La implementaci6n de 10s mitodos de empresa es relativamente sencilla: son todos metodos s e t y g e t . El Gnico aspect0 interesante sobre ellos es su manejo de la lista dependiente de instrucciones de redireccionamiento:
//
Metcdos de empresa set RoutingInstructior~s (Collection c )
(

p u b l i c void setRI ( c l ;

p u b l i c C o l l e c t i o n g e t R o u t i n g I r , s t r u c t i o r ~ (s ) r e t u r n getRI ( ) ;

p u b l i c v o i d addRoutir~gIrlstruction(int s e q u e n c e , S t r i n g i n s t r u c t i o n ) Collection c = getRI() ; c . a d d (new R o ~ t i r ~ g I r i s t r u c t i o (s ne q u e n c e , i n s t r u c t i o n ) ) ; s e t R I ( c );

I
p u b l i c v o i d deleteRoutingInstructior~(ir~t sequence) throws t.loSuchRoutingExceptior~ ( Collection instructions = getRoutingInstructior~s ( ) ; I t e r a t o r i t e r = i n s t r u c t i o r . ~ i. t e r a t o r ( ) ; while ( i t e r .hasNext ( ) I { RoutirlgIr~structior~ r i = ( R o u t i r ~ g I n s t . r u c t i o r ~i)t e r . n e x t ( ) ; i f ( r i . s e q u e n c e == sequercce) { iter.remove(); ; setRoutingInstructior~s (ir1str1uctior1s) return; \ t t h r o w new N o S u c h R o u t i n g E x c e p t i o r ~( ) ;

1
public void r e p l a c e R o u t i n g I r ~ s t r u c t i o n s (RoutingInstruction [ I r ~ e w R o u t i r ~ g I r lrsu t c t i o n s ) t h r o w s RemcJteException 1 L i r ~ k e d L i s t l i = new L i n k e d L i s t ( ) ; f o r ( i n t i = Cl; i ; r ~ e w R o u t i r ~ g I r ~ s t r i ~ c t il o er n~ gs th . ; it+) ( l i .add ( r ~ e w R o u t i r ~ q I r ~ s t r u c t [ io ir] ) ~; s

1
setRc~utir~gIr~structio ( rl, i s) ;

I
Las retrollamadas estin en su mayor parte vacias porque el contenedor proporciona por nosotros la mayoria de la funcionalidad. El metodo c r e a t e ( ) toma como parimetros una descripci6n completa del estado del objeto: producto, nombre e instrucciones de redireccionamiento.
//
Metodos d e String c i c l o de vida

y de sistema

public

e j b C r e a t e ( S t r i n g p r i i d u c t , S t r i n g name, Collection routingInstructions1 throws RemoteException { s e t P r o d u c t ( p r o d u c t ); s e t N a m e ( n a m e ); s e t R o u t i r ~ g I n s t r u c t i o r I~r s o u t i ~ r ~; s ) return null;

1
public void e j b P o s t C r e a t e ( S t r i r l q p r o d u c t , S t r i n g name, Collection routingInstructions)
{ j

Beans de entidad y persistencia

public public public public public public public

void void void void void void void

ej bActivate ( ) { I ej bLoad ( ) { 1 ejbPassivate ( [ I ejbRemove ( ) { ) ejbStore0 [ I setEntityContext ( E r ~ t i t y C ~ r ~ t ec xt tx ) { 1 unsetEntityC.intext ( ) { I

I
La clase de excepcion NoSuchRoutinglnstruction Unavez mis, la clase excepcion definida en este paquete ( N o S u c h R o u t i n g I n s t r u c t i o n ) es bastante singular:
package factory.product;
{

~ Exception public class N o S u c h R o u t i n g I n s t r u c t l ~ r extends

public NoSuchRoutingInstructioni)

{ j

Las implementaciones de 10s beans de entidad Producto y Pedido son bastante sencillas. Se centran en 16gica de empresa y n o tienen problemas de nivel de sistema, de tip0 persistencia.

El descriptor de despliegue completo


Hemos visto algunos fragmentos del descriptor de implementaci6n XML para este ejemplo a medida que hemos ido examinando el c6digo Java. Se trata del descriptor completado para 10s cuatro beans (un bean de sesion sin estado para gestionar pedidos, un bean de sesi6n con estado para fabricar un producto, una entidad de pedido y una entidad de producto):
<?xml version="l.O"?i < ! DOCTYPE ejb-jar PUBLIC '-//Sun Micr.isysterns, Ir~c. //DTD Enterprise JavaBeans 2. O//ENf 'http: //java .sun.corn/dtd/ejb-jar 2 O . d t d l >

La informaci6n de implementacion para el bean para gestionar pedidos (observe que declaramos referencias locales a Producto):
<session> <ej b - n a m e > M a n a g e O r d e r s < / e j b-r~ame> <home>factory.manage o r d e r s . M a n a q e O r d e r s H . i r n e < / h o m e > <remote>factory.manage o r d e r s . M a n a g e O r d e r s < / r e m ~ t e > <ejb-class>factory.manage orders.ManaqeOrdersEJB</ejb-class>
<session-type>Stateless</sessior~-type> <transaction-type>Cor~tair~er</trar~sactior~-type~

<env-entry> <env-entry-name>lead time</env-entry-r~ame> <env-entry-type>j a v a . lar~g. Ir1teqe~-</tr1v-er~try-type>


<er~v-entry-value>3</er1v-er1try-value>

</env-entry> cenv-entry> < e n v e n t r y n a m e > m a x < e n v e n t r y n a m e > m a x _ i n v e n t o r y _ t i m e < / e n v i r ~ v e r ~ t ~ r y Y t i m e < / e r ~ v e r ~ t r y r ~ a m e >

Capitulo 16
< e n v - e n t r y - t y p e > ] a v a . larlq. I r ~ t e g e r < / e r ~ v - e n t r y - t y p e > <env-entry-value>lO</er~v-er2try-value> </erjv-entry> < e jb - r e f > <ejb-ref-name>e j b/Order</ejb-ref-r~ame> i e j b-ref-type>Entity</ejb-ref-type>

<home>factory.oriler.OrderHome</home> <remote>factory.order.Order</remote>
< e jb - l i n k > O r d e r s < / e j b - l i r , k > < / e jb - r e f > <ejb-local-ref> < e jb - r e f - n a m e > e j b / L o c a l P r o d u c t < / e j b - r e f - n a m e > < e jb - r e f - t y p e > E n t i t y < / e j b - r e f - t y p e >

<local-home>factory.productlocalHome</local-home> <local>factory.product.Lo~a1Prod~~t</10cal>
< e jb - l i n k > P r o d u c t < / e j b - l i r , k > </ejb-local-ref> </session>

La informaci6n de implementaci6n para el bean para fabricar productos:


<session> < e j b-name>Manuf a c t u r e < / e j b-riame>

<home>factory.mar~ufacture.Mar~~factureHome</home> <remote>factory.mar~ufacture.Mar~ufacture</remote> <ejb-class>factory.mar~ufacture.Mar~ufactureEJB~/ejb-class>


~session-type>Statefu1</sessior1-type>

<trar~sactior~-type>Cor~tair~er</trar~sa~tic~r~-type>
<env-entry> < e r ~ v - e n t r y - n a r n e > s h i p m e r ~ t S Q L < / e n v - e rr ly t -name> < e n v - e n t r y - t y p e > j a v a . l a r ~ gS . trir~g</er~v-entry-type> < e n v - e n t r y - v a l u e > INSERT INTO c b s h i p m e n t s ( d i v i s i o n , o r d e r n u m b e r , c a r r i e r , loading dock, d a t e completed, r n a r , u f a c t u r e d b y ) VALUES ( ? , ?, ?, ? , ? , ? ) </ env-entry-val ue> </ env-entry> < e jb - r e f > < e jb - r e f - n a m e > e j b / O r d e r < / e j b - r e f - r ~ a m e > < e jb - r e f - t y p e > E n t i t y < / e j b - r e f - t y p e >

<home>factory.order.OrderHome</home> <remote>factory.order.Order</remote> <ejb-link>Orders</ejb-link>


</ejb-ref> < e jb - r e f > c e j b - r e f - n a m e > e j b / M a n a g e O r d e r s < / e j b - r e f -name> < e jb - r e f - t y p e > S e s s i o r i < / e j b - r e f - t y p e > < h o m e > f a c t o r y . m a r t a g e orders.Mar~aqeOrdersHome</home> < r e m o t e > f a c t o r y . m a n a g e orders.ManaqeOrders</remote> < e jb-link>ManageOrders</ej b - l i n k > </ejb-ref> <resource-ref> < r e s - r e f -name>jdbc/ship~~</res-re -name> f

<res-type>javax.sql.DataSource</res-type> Cres-auth>Container</res-auth> </resource-ref> </session>

Informaci6n de implementaci6n para el bean de entidad del pedido:

Beans de entidad y persistencia


<remote>factory.order.Order</remote> <ejb-class>factory.order.OrderEJB</ejb-class> <persister~ce-type>Cor~tainer</persister~ce-type> <prim-key-class>factory.order.OrderPK</prim-key-class> <reentrant>False</reer~trarit> <crnp-versior1>2 .x</cmp-version> <abstract-schema-name>Orders</abstract-schema-r~ame> <cmp-field><field-r1ame>salesD1vision</field-r~ame></cmp-field> <cmp-field><field-r~ame>orderNumber</field-r~arne></cmp-field> <cmp-f ield><f i e l ~ d - n a m e > i r 1 t e r r 1 a l S t a t u s ~field-name></cmp-field> </ <cmp-f ield><field-name>dateDue</ f i e l 1 A - r ~ . a r n e > < / c m p - f i e l d > <ejb-local-ref> <ejb-ref-name>ej b/LocalProduct</ej b-ref-name> <ejb-ref-type>EntityC/ejb-ref-type> <local-hnme>factory.product.ProductLocalH~~me</local-home> <local>f actory. product. LocalPr~~duct</local>
<ejb-link>Product</ejb-link>

</ejb-local-ref> <query> <query-method> <method-name>findOper~Orders</method-name> <method-params> </method-params> </query-method> cejb-ql> <:! [CDATAISELECT OBJECTio) FROM Orders AS o WHERE ( 0 . internalStatus = 'o' OR o.internalStatus = 'm' ) I ] > </ej b-ql> </query> <:query> <query-method> <method-r1ame>fir1dUr1cc~mp1etedOrders</method-rtame> <method-params> </methcd-params> </query-method> <ej b-ql> < ! [CDATALSELECT OBJECT ( o ) FROM Orders AS o 0 '' WHERE (o.internalStatus = ' OR o. internalStatus = 'm' ) ] 1 > </ejb-ql> </query> </entity>

Informaci6n de implementaci6n para el bean de entidad del producto:


<entity> <ej b-narne>Product</ej b-name> <home>factory.product.ProductHome~/home> <rernote>factory.product.Product</remote> <local-home>factory.productlocalHome</local-home> <local>factory.product.Loca1Product</10cal> ~ejb-class>factory.product.ProductEJB</ejb-class>
<persistence-type>Cor1tair1er</persister1ce-type> <prim-key-class>j ava. lar~g. Strir~g</prim-key-class>

<reentrant>False</ reentrant> <cmp-versior1>2.x</cmp-version>


<abstract-schema-r~arne>Product</ab~tract-schema-r~ame>

<cmp-field><field-r~ame>product</field-r~ame></cmp-field> <cmp-field><f i e l d - n a m e > r ~ a m e < / f i e l d - r ~ a m e > < / c m p ield> f <cmp-field><f ield-name>rI</ field-r~ame></cmp-f ield> <primkey-field>product</primkey-field>

Capitulo 16

La relaci6n entre O r d e r E J B y p r o d u c t O r d e r e d es uno-a-uno y unidireccional (desde un Pedido, obtendremos el product0 solicitado pero no a1 contrario; no lo necesitamos para este ejemplo). Consecuentemente, s61o es necesario que especifiquemos un <cmr- f i e l d > . Si quisiiramos que las relaciones fueran direccionales, tambien necesitariamos especificar un campo CMR en P r o d u c t E J B (podriamos llamarlo o r d e r y tendriamos que declarar abstract0 g e t o r d e r ( ) / s e t o r d e r ( ) sobre
ProductEJB):

Informaci6n de ensamblaje para la aplicaci6n en su conjunto; especificamente, transacciones declarativas:

Beans de entidad v persistencia


</container-transactior~> <contair~er-trar~sac i.n> tl

<method>
< e j b - r ~ a m e i M a r m u f a c t u r e < / e b-r~ame> j

<method-name\'</method-name>

<'/methcd>
/trar1s-attrlbute>Rtq~~1red</trar~s-attrib~~te> </container-trar~sactiori>

</assembly-descriptor> < / e jb-j a r > Comentarios sobre el descriptor de irnplementacion: Las etiquetas < e n v - e n t r y > son nuevos. Son un modo conveniente de pasar informacion almacenada en 10s descriptores de implementaci6n a nuestros EJB. El EJB tendri acceso a estos valores buscindolos en el espacio de nombre j a v a : comp . / e n v . U n ejemplo de c6digo para leer el valor l e a d - t i m e seria: I n i t i a l C o n t e x t i n i t i a l = new I r l i t - i a l C n n t e x t ( 1 ; 1 r . t e g e r 1eadTirntDays = ( I n t e g e r ) i r ~ i t i a l . l i ~ ~ ~ k ~ . ~ p ( " j a v a : c o m p / e r~ ti vm / le t" a )d;

O < e j b - l i n k > ofrece un modo de hacer referencia a vinculos a travks de un descriptor de


implementacion o a EJB que definidos en otro archivo JAR (observe que 10s EJB vinculados deben pertenecer al mismo archivo EAR). Tambien necesitamos declarar alguna informaci6n extra especifica de WebLogic e n w e b l o g i c - e j bj a r . xml y w e b l o g i c - c m p . x m l . N a d a d e s t a c a b ~ e e n w e b l o g i c - ej b - j a r . xmlexceptoque,estavez, necesitamos asociar algunas de las referencias locales que declaramos en e j b - j a r .xml a Producto. ~ s t e es el a r c h i v o w e b l o g i c - e j b - j a r .xml:
I !

DOCTYPE w e b l o g i c - e j P U B L I C '-//BEA

I n c . //DTD WebLogic 6.0.0 EJB//EN1 'http://www.bea.com/servers/wls60iJ/dtd/~~yeblogic-ejb-jar.dtd'>

b-j a r Systems,

'reference-descriptor> <ejb-local-ref e r ~ n z e - d e s c r i p t i ~ r ~ ' < e l b-ref-name>cj b / L o c a l P r o d u c t i / i - j b-ref-name> c j ndi-narne>Local P r o d ~ ~ c t < n/d ]i - r ~ a m e > < / e jb - l o c a l - r e f e r e n r : e - d e s c r i p t i o r ~ > </refel ence-descriptor>

Capitulo 16
<weblogic-enterprise-bean' <ej b-nanie>Orders</ej b-r,ame> <entity-descriptor> <persistence> <persistence-type>
< t y p e - i d e r ~ t i f i e r > W e b L o g i cCMP RDBMS</type-identifier> <type-version>6.@</type-version> <type-storage>META-INF/weblogic-cmp.xml</type-storage> </persistence-type> <persistence-use> <type-identifier>WebLogic CMP RDBMS</type-identifier> <type-version>6.0</type-version, </persistence-use> </persistence> </entity-descriptar>

<reference-descriptor> <ej b - l o c a l - r e f e r e n c e - d e s c r i p t i o r ~ > <ej b-ref -name>ej b/LocalProduct</ej b-ref-name> <j ndi-name>Local Product</ j r~di-name> </ej b-local-reference-description> </ref erence-descriptor>

<weblogic-enterprise-bear,> <ej b-name>Product</ej b-r~ame> <entity-descriptor> <persistence> <persistence-type> <type-identifier>WebLoqic CMP RDBMS</type-identifier> <type-version>6.0</type-versior~> <type-storage>META-INF/webloqi~-cmp~xml</type-storage> </persistence-type> <persistence-use> <type-identifier>WebLogic CMP RDBMS</type-identifier> <type-versian>E. O</type-version> </persistence-use> </persistence> </entity-descriptor> <j ndi-name>Product</ jridi-name> <local-j ndi-name>LocalProduct</loca1-j r~di-name> </weblaqic-enterprise-bean:>

El archivo w e b l o g i c - c m p .xml es similar a1 que ya ha visto al principio de este capitulo except0 en la especificacion de relaciones. En e j b - ja r .xml, hemos especificado la naturaleza de la relaci6n per0 el contenedor todavia necesita alguna informaci6n extra para implementarlo. En esta relaci6n, estamos vinculando un Pedido a un Producto, por lo tanto el contenedor necesita saber c6mo almacenar el product0 dentro del pedido. El contenedor ya sabe que debe utilizar el campo CMR llamado p r o d u c t para ello, per0 no sabe quC almacenar en este punto. Las relaciones se mantienen mediante el uso de claves externas. En este campo, n o vamos a alrnacenar un objeto Producto completo. Esta informaci6n es suficiente para que el contenedor materialice el otro extremo de la relaci6n siempre que la necesite. Ahora que comprendemos el principio, necesitamos especificar la asociaci6n: necesitamos descubrir quC se necesita para especificar la clave primaria de un producto. U n ripido vistazo a e j b - ja r .xml nos dice que la clave primaria de ~ r o d u c es t una ~ ~ simple ~ cadena por lo que resultari ficil: creemos una columna en

Beans de entidad y persistencia


la tabla de producto que contendri esta cadena. Despuks informamos a1 contenedor que la clave primaria de P r o d u c t E J B (almacenada en la c o h m n a "producto") seri asociada en la c o ~ u m n a p r o d u c t ~ o r d e r e d d e ~ r d e r ~ ~ ~ . ~ s t es e el archivo ~ o m ~ l e t o w e b l o g i c - c mxml: p.
< ' D O C T Y P E weblogic-rdbms-j a r PUBLIC '-//BE?, Systems, Iric.//DTI? WehLogic 6.0.0 EJB RDBMS Persistence//EN1 'http://www.bea.~om/ser~~ers/wls600/dtd/ weblogic-rdhms20-persister1ce-600.dtd'~

<field-map>
<cmp-field>salesDivisior~</cmp-field>

<dbms-column>sales division</dbms-column> </ field-map <field-map>


<cmp-field>arderNumberc/cmp-field> cdbms-column>order r~un,ber</dbms-column> </field-map> ifield-map> <cmp-field>dateDue</cmp-field> <Hbms-column\da te due</dbr~s-column> < / field-map> <field-map> <cmp-f i e l d > i n t e r n a l S t a t u s < / c n i p - f i e l d > <dbms-column>interr~al status</dbms-column\ < / field-map> </weblogic-rdbms-bean>

Capitulo 16

Observe que estamos reutilizando la fuente de datos de ejemplo ~ p o r t ~ e a m a n t e r i olo r ; hacemos para ahorrar algo de tiempo, aunque en un entorno de producci6n querriamos utilizar una fuente de datos diferente. i Q u 6 sucede si el bean relacionado tiene una clave primaria compuesta? En este caso, simplemente amplie el principio que acabamos de aplicar: averigiie qu6 columnas constituyen su clave primaria, Cree una columna correspondiente para cada una de ellas en su EJB fuente y especifique despues la asociacion entre ellas como anteriormente.

Ejecutar la aplicacion de fibricacion


En este punto, tiene informaci6n suficiente para ejecutar la aplicaci6n de muestra de fabrication. Debe tener las siguientes clases en su JAR EJB (o estructura de directorio, si su contenedor EJB se ajusta a este formato):
factory/ clients/ BeginManufacture.class SompleteManufacture.class C o n t e x t PropertiesFactory. class CreateProducts.class ManageSampleOrders.class PlaceSampleOrders.class manage-orders/
D u p l i c a t e O r d e r E x c e p t i o r ~c . lass ManageOrders.class ManageOrdersEJB.class Manage0rdersHome.cla-c NoSuchOrderExceptior~. class NnSuchProductExceptiorl.class OpenOrderView.class OverdlueOrderView. c l a s s

ProdiuctCreationHelper.class

manufacture/
BadStatusException.class Manufacture. class ManufactureEJB.class ManufactureHome.class NoSelectionExceptior~. class

order/ Order. class OrderEJB.class 0rderHome.class OrderNotCancelableExceptior1.c1ass OrderPK. c l a s s StaCusStrings.zlass product/ NoSuchRoutinqExceptior~~class Product. class

Beans de entidad y persistencia


ProductEJB.class ProductHome.class RoutingInstructior~. class META-INF/ ej b-jar .xml w e b l o g i c - e j b-j ar.xml weblogic-cmp.xm1

Observe que 10s clientes,manage-orders y p a q u e t e s m a n u f a c t u r e proceden del capitulo anterior sobre beans de sesi6n. Tambien es necesario que Cree la tabla de base de datos utilizada por el bean de sesion de fabrication para registro de envios. Esto fue analizado en el capitulo anterior; como recordatorio, este es el S Q L para crear esta tabla:
CREATE T A B L E c b shipmerits(divisior1 INTEGER NOT NIJLL, order number INTEGER NOT NULL, carrier VARCHAR ( 5 0 ) , loading d o c k INTEGER, d a t e completed DATE, manufactured b y VARCHAR ( 5 O ) , PRIMARY KEY (division, order-number)

) ;

Tambien necesitamos una para almacenar productos:


CREATE T A B L E c b products( product VARCHAR(501, name VARCHAR ( 5 0 ) , routir~gIr~structions LONGVARBINARY, PRIMARY KEY ( p r o d u c t )) ;

Y, finalmente, una para almacenar pedidos:


CREATE TABLE c b o r d e r s ( o r d e r number INTEGER, s a l e s d i v i s i o n INTEGER, product ordered V A R C H A R ( 5 0 ) , d a t e d u e DATE, internal s t a t u s V A R C H A R ( 2 0 0 ) , PRIMARY KEY (sales-division, order-number)

);

Fijese en que necesitari tener cuidado para no sobrescribir estas tablas si ya existen. Asi mismo, querri crearlas en la base de datos a la que apunta la fuente de datos j d b c / s p o r t sJDBC; si no es asi, la aplicaci6n no podri almacenar ningun dato. Ahora, debe poder ejecutar 10s clientes descritos anteriormente. Estos clientes simplemente proporcionan una prueba sencilla de la funcionalidad provista por nuestros EJB: Ejecute primer0 c r e a t e P r o d u c t s para crear algunos productos de muestra

O A continuaci6n ejecute P l a c e S a m p l e O r d e r s . (Ejecutar cualquiera de estos programas por segunda vez sin eliminar 10s registros apropiados de la base de datos provocari mensajes de error inofensivos.)
O

Ejecute d e s p u k s ~ a n a g ea s m p l e ~ r d e r sseleccionari ; un pedido atrasado y lo cancelari.

Capitulo 16

I Ejccute B e g i n M a n u f a c t u r e n continuacibn; utilizarj. un bean de sesi6n con ertado para

seleccionar un pedido apropiado para la fabricaci6n y codificar un controlador para ese bean. (El controlador se almacenari en c : / c u r r e n t - p r o d u c t ser. Si no es un nonibre apropiado para suordenador,debecanibinrloen B e g i n M a n u f a c t u r e . j a v a y C o m p l e t e M a n u f a c t u r e j ava.)

uc f t u r e ; decodificari elcontrolador, imprimirl las 1 I Finalmcnte, e j e c u t e ~ o m p l e t e ~ a n a instrucciones para fabricacion y enviari el producto. (Observe que, en este caso, la unica razdn por la que hemos dividido el proceso de fabricacion en dos aplicaciones de rnuestra es para deniostrar cdmo codificar el controlador.)

Si escci utilizmdo Windows 2000 y el J D K SUN,entonces puede obtener u n error JVM cuando
intente invocar getEJBObject() en el controlador cod$cado. Se trata de u n bug cuya solucidn en contra rk en: h ttp:lldeveloper.sunJava.com/developerlbugParadelbugs/44 72 743.html.

Resumen
En este capitulo, hemos analizado en detenimiento 10s beans de entidad. Los puntos principales son: Los beans de entidad representan 10s datos compartidos, transaccionales de su aplicaci6n La persistencia de beans de entidad puede ser gestionada por el programador de bean o por el contenedor La persistencia gestionada por contenedor puede aunientar la productividad per0 quizis no tenga la suficiente capacidad para sus necesidades, aunque EJB 2.0 debe cubrir la mayor parte de las necesidades de 10s desarrolladores

Beans de entidad y persistencia


Las herramientas de asociaci6n objeto/relacional de terceros pueden proporcionar servicios de persistencia capaces per0 son de propiedad y potencialmente caras La persistencia gestionada por bean obliga a1 programador bean a asumir la carga de transferencia de datos desde el objeto hasta el almacen de datos El contenedor y el almacen de datos son compatibles con el almacenamiento en memoria cache de datos dentro de una transacci6n El almacenamiento en cache de datos entre transacciones puede propiciar un aumento en el rendimiento si su aplicaci6n y entorno lo permiten Los metodos buscadores permiten a un cliente localizar el estado de objeto compartido correspondiente a una identidad concreta o a un criterio particular Las relaciones son automiticamente gestionadas por el contenedor EJB 2.0: Q L EJB es un lenguaje muy potente que le permite encontrar beans o examinar relaciones de un mod0 independiente de la base de datos Los beans de entidad reentrantes estin permitidos per0 pueden evitar que el contenedor almacene en cache una determinada clase de error y, por ello, no son recomendados En el siguiente capitulo, examinaremos cuatro servicios fundamentales que puede proveer un contenedor EJB: transacciones declarativas, seguridad declarativa, compatibilidad con comunicaciones remotas y un sistema de manejo de excepciones. Aunque cada contenedor EJB proporciona estos servicios, debe tener algunos conocimientos de cada tema (y de c6mo se relacionan con la tecnologia EJB) para desarrollar e implementar de forma efectiva sus componentes EJB.

Aunque el prop6sito de la tecnologia Enterprise JavaBeans es liberar a 10s programadores de 16gica de empresa de tener que desarrollar servicios de nivel de sistema, todavia es Gtil e importante para 10s desarrolladores comprender como funcionan dichos servicios. Cada aplicaci6n significativa de empresa necesitari proporcionar apoyo para que las transacciones protejan la integridad de sus datos. De un mod0 similar, necesitari proteger sus recursos contra acceso no autorizados. Una aplicacion necesitari ser compatible con el acceso direct0 a sus datos y a la 16gica de empresa, y para manejar condiciones excepcionales de forma s6lida. Todos 10s contenedores que cumplen la especificaci6n EJB son compatibles con transacciones, seguridad, comunicaciones y manejo de excepciones. Aunque la verdadera implementaci6n de estos servicios diferiri entre contenedores EJB, la especificaci6n EJB esti escrita de mod0 que un bean de empresa pueda aprovechar estos servicios de forma portitil. Esto significa que 10s desarrolladores pueden escribir 16gica de empresa para aprovechar estos servicios de contenedor sin sacrificar la capacidad de ejecutar sus beans en mdtiples contenedores. En la mayoria de casos, un programador EJB puede aprovechar estos servicios sin escribir c6digo Java en absoluto, ya que una de las intenciones de la especificaci6n EJB es permitir a 10s desarrolladores, siempre que sea posible, hacer una declaraci6n de intenciones sobre c6mo deben operar ciertos servicios, tip0 transacciones y seguridad, en una determinada aplicaci6n. Esto permite que una aplicaci6n se implemente en cualquier entorno de ejecuci6n utilizando Gnicamente las herramientas proporcionadas por el vendedor del servidor de aplicaci6n, sin ninguna programaci6n adicional. Este enfoque basado en el uso de servicios es mucho mis ficil, mis barato (puesto que toda la tecnologia subyacente cuesta dinero de desarrollar), y mis s6lido que programar el uso de estos servicios para cada bean.

La presencia de servicios declarativos de contenedor no absuelve a1 desarrollador de bean (e implementador) de entender c6mo funcionan las transacciones, seguridad, las comunicaciones y el manejo de excepciones en el context0 de la tecnologia EJB.

Capitulo 17
Los desarrolladores y el implementador de una aplicacion necesitan comprender el entorno en el que estin implementando, incluido la base de datos, sewidor de aplicaci6n y sistema de seguridad; no obstante, esto se da menos en el desarrollador, que se aisla a1 miximo del entorno de implementacih de destino. En este capitulo, examinaremos 10s temas relacionados con estos sewicios declarativos o autorniticos. Esto significa que estaremos utilizando las herramientas de implementaci6n de nuestro sewidor de aplicacion, en lugar del editor de c6digo. Los ejemplos orientados a1 c6digo estin disefiados para demostrar tecnicas aplicables en.casos especiales (corno el acceso a1 director de seguridad) o que deben ser desaconsejados en general (corno el uso de lainterfaz j a v a x . T r a n s a c t i o n . U s e r T r a n s a c t i o n ) . Querremos ver c6mo cada uno de estos temas de aplica a sewidores especificos de aplicaci6n y contenedores EJB, y el mejor mod0 de conseguir este objetivo es:
0 Tomando muestras de c6digo de 10s dtimos capitulos y configurando 10s atributos transaccionales y

el sistema de seguridad que utiliza las herramientas de implementacih que proporciona el vendedor
0 Estudiando la docurnentacion del vendedor referente a 10s servicios de comunicacih que provee
0

Examinando el registro que ejecuta el contenedor EJB cuando se genera una excepcidn de sistema

0 Analizando cualquier archivo XML especifico de vendedor que genera el contenedor

La tecnologia EJB intenta separar problemas de nivel de sistema del dominio del programador de logica de empresa y mejorar la portabilidad entre diferentes entornos. Como resultado, puede presentar solicitudes significativas a la persona que necesita configurar una aplicaci6n EJB para adaptarse a un determinado entorno. A1 final de este capitulo, comprenderemos 10s servicios bisicos que proporciona el contenedor EJB y estaremos en posici6n de tomar decisiones inteligentes durante el desarrollo e implementaci6n de la aplicaci6n. Puesto que 10s servidores de aplicaci6n y 10s contenedores EJB varian tanto, debemos tambikn leer la documentaci6n que se adjunta a una herramientas concreta. Esto es inevitable debido a lavariedad de implementaciones para tecnologia EJB. La informacion de este capitulo se aplicari a todo contenedor EJB 2.0 y nos ayudari a comprender las opciones genericas que presentan todos ellos. Concretamente, trataremos:
0 Transacciones

Compararemos el apoyo de transacciones programitico tradicional y el apoyo a transacciones declarativas. Tambikn examinaremos las situaciones de transacci6n declarativa y las opciones existentes.
0

Seguridad Analizaremos las consideraciones de seguridad de nivel de empresa y 10s roles y permisos que tienen que desempeiiar. Tambien veremos las situaciones en las que es necesario un control de acceso programitico. Examinaremos nuestra re~~onsabilidad en lo referente a las excepciones, tanto las relacionadas con el sistema como las relacionadas con la aplicaci6n, sus consecuencias y la acci6n resultante de 10s contenedores en 10s que reside nuestro c6digo.

u Manejo d e excepciones

0 Comunicaci6n Analizaremos la comunicaci6n entre sewidores de aplicaci6n h e t e r ~ ~ k n e o s .

Transacciones
Una transacci6n es un conjunto de operaciones que deben ser procesadas como una sola unidad. Para ser considerado transaccional, el conjunto de operaciones que compone una tinica unidad de trabajo debe

Servicios de contenedor EJB


mostrar ciertas caracteristicas bien definidas, referidas por el acronimo (en inglks) mnemotkcnico ACID, debe ser Atomico, Consistente, Aislado, Duradero.
0

Atdmico significa que las operaciones deben funcionar o fallar como grupo. Si de una cuenta bancaria se retira dinero y despuks se ingresa en otra cuenta bancaria en una transacci6n, nunca debemos tener una situacion en la que falle el cargo y el crkdito se realice con kxito, o viceversa. Ambas deben llevarse a cab0 con kxito y el dinero sera transferido, o ambas deben fallar y el sistema n o habri robado ni regalado dinero al cliente. base de datos, independientemente del kxito o fracas0 de cualquier transacci6n. Como resultado, el pogramador de 16gica de empresa no tendri que deshacer 10s efectos de una transacci6n fallida en su c6digo. Tambikn significa que un administrador de base de datos no tendri que limpiar ningun. registro hukrfano o dato ma1 correspondido procedente de las operaciones que no llegan a completarse.

o Consistente significa que la base de datos debe quedar en un estado que no viole la integridad de la

Aislado significa que la 16gica de empresa puede proceder sin considerar otras actividades del sistema. Por ejemplo, mientras que un EJB esti comprobando que hay suficiente dinero en la cuenta antes de transferirlo, otro proceso puede estar retirando dinero de esta misma cuenta para satisfacer una solicitud de dinero desde un cajero automitico. Si 10s dos procesos no se mantienen aislados de 10s efectos del otro, es posible que la transferencia y operaci6n de cajero automitico tengan ambas kxito (utilizando el mismo dinero). Debido a la propiedad de aislamiento (bloqueo) . de transacciones, el programador de 16gica de empresa no necesita defenderse de esta situaci6n. Duradero significa que una vez que ha tenido kxito una transacci611, 10s resultados se reflejarin en el almackn de datos persistentes. Como resultado, el pogramador de 16gica de empresa no tendri que preocuparse por un error posterior de algun tipo que p e d e provocar que 10s datos se vuelvan inconsistentes.

Una transacci6n tiene un punto de inicio discreto. DespuCs de este punto de inicio, 10s cambios efectuados a travks de cualquier recurso que estk listado (que participe) en la transacci611, como una conexi6n a una base de datos, tendrin las propiedades ACID que acabamos de describir. La transacci6n tambikn tendri un punto final discreto. En el punto final, la transaccion puede realizar (hacer permanentes todos 10s cambios) o deshacer (anular todos 10s cambios que ha realizado en esa transacci6n). Existen dos puntos clave. Primero, estos cambios son todo o nada. Segundo, 10s cambios que realizan otras transacciones no interfieren con estos cambios (sujetos a la politics de aislamiento, descrita arriba). Las transacciones declarativas p e d e n simplificar el desarrollo de apkaci6n liberando a1 programador de 16gica de empresa de escribir c6digo para tratar 10s temas complejos de nivel de sistema de recuperaci6n de fallos y acceso concurrente desde un sistema multi-usuario. U n contenedor EJB proporcionari apoyo, gestionando estas transacciones sin ser necesario que el programador implemente esta 16gica en c6digo Java. Por supuesto, las transacciones conllevan un coste de rendimiento y reajustabilidad. Garantizar que estas propiedades ACID son aplicadas a un conjunto de operaciones requiere la coordinacidn de recursos relevantes (como una base de datos) y el servidor de la aplicaci6n. Por lo tanto, tendri lugar alguna comunicaci6n extra entre 10s participantes y el gestor de la transacci6n. Es mis, quizis requiera que 10s accesos a 10s datos sean seializados, en lugar de permitir que se sucedan simultineamente. Las aplicaciones quizis quieran que parte de sus operaciones tengan lugar bajo en control de una transacci6n por estos motivos. Adicionalmente, algunos recursos n o apoyan las transacciones gestionadas por un gestor de transacciones externo. U n gestor de transacciones es una entidad externa a nuestra aplicaci6n que actua como mediador cuando se solicita acceso concurrente a recursos. El contenedor EJB no puede gestionar las transacciones para beans que utilizan un recurso de este tipo. En tal caso, el desarrollador de bean debe

Capitulo 17
utilizar transacciones gestionadas por contenedor e indicar que 10s rnktodos del bean no operan en una transaccibn. El programador EJB puede elegir entre utilizar un sencillo API para dernarcar 10s lirnites de transacciones y proporcionar inforrnacidn en el descriptor de irnplernentacibn XML para perrnitir que el contenedor gestione 10s lirnites de la transaccibn. La prirnera opcidn se conoce corno demarcacidn de transaccibn gestionada por bean y la segunda como demarcaci6n de transacci6n gestionada por contenedor. Arnbas opciones protegen a1 prograrnador de la verdadera complejidad de la implernentacibn de un sisterna de procesarniento de transaccibn, sosteniendo el principio bisico de diferir a1 contenedor siernpre que sea posible~Es rnucho rnenos probable que necesiternos utilizar transacciones gestionadas por bean que necesiternos utilizar, por ejernplo, persistencia gestionada por bean. Existen rnuchas complejidades ocultas a las que enfrentarse si decidirnos gestionar nuestra propia transaccibn. L.as verdaderas dificultades se encuentran en el rnanejo de errores y excepciones. Deshacer una transaccibn es una operacibn cornpleja y costosa que debe realizarse con cuidado. Se recornienda seriarnente que utilicernos la sernintica declarativa disponible con transacciones gestionadas por contenedor; nos ahorrari rnucho tiernpo. Las transacciones gestionadas por bean s61o son posibles para beans de sesi6n; 10s beans de entidad que utilizan persistencia gestionada por contenedor deben utilizar transacciones gestionadas por contenedor. El desarrollador de un bean de sesidn debe declarar el tip0 de dernarcacidn de transaccibn en el descriptor de implernentacibn XML. Habitualrnente, esta informacidn seri editada por el proveedor del contenedor; sin embargo, tarnbien puede editarse rnanualrnente. Estas son entradas de ejernplo que declaran cada tip0 de dernarcacibn de transaccibn:

Transacciones sin contenedor


El contenedor EJB se responsabiliza de la gestibn de transacciones pero, por supuesto, es posible tener transacciones sin EJB. C o n el objetivo de contribuir a la aclaracibn del concept0 de transaccibn, analicernos las transacciones en un prograrna Java autbnorno. Exarninarernos un objeto Cuenta que actualiza la base de datos rnediante una conexidn que es pasada corno parirnetro. La clase j ava . sql .Connection proporciona la gestibn bisica de transaccibn que utilizarernos en nuestro sencillo ejernplo (pero no se nos perrnite utilizarla en un servidor de aplicacibn). Examinarernos dos clientes: uno que n o utiliza transacciones y uno que si. Veremos cdrno las transacciones son necesarias para la integridad de 10s datos. La tabla de la base de datos esti definida con dos restricciones de integridad, para proporcionar un valor rninirno y uno rnixirno para una cuenta:
CREATE TABLE ACCOUNT (ACCOUNT1D VARCHAR (25) NOT NULL, CUSTOMERNAME VARCHAR(25), AMOUNT DOUBLE PRECISION, PRIMARY KEY (ACCOUNTID), CHECK (AMOUNT > 0 ) , CHECK (AMOUNT < 15000)
) ;

~ s t es a la definicidn del objeto Cuenta. Tiene rnetodos set y get,y rnktodos de ciclo de vida crear, leer, actualizar y elirninar:

Servicios de contenedor EI6


import import import import j ava. s q l .Connection; java. s q l . PreparedStatement; java.sql.ResultSet; j a v a . s q l . S Q L E z c e p ti o n ;

publ i z z l a s s Account [ p r i v a t e S t r i n g accuur~tID; p r i v a t e S t r i n g customerName; p r i v a t e d o u b l e amount; p u b l i c S t r i n g g e t A c c o u r ~ t I D )( r e t u r n accountID;

I
p u b l i c S t r i r q getCustomerName ( ) r e t u r r i custc~merName; 1
[

~ ' u b l l c v o i d s e t C u s t o m e r N a m e (String c u s t o m e r N a m e ) t h i s . c u s t o m e r N a m e = customerName;

p u b l i c d o u b l e getAmount r e t u r n amount; i p u b l i c v o i d s e t A m n u n t ( do u b l e t h i s . amount = a m o u n t ;


1

amount)

public

c r e a t e ( S t r i r 1 g accountID, S t r i r ~ qc ~ ~ s t o m e r N a m e , d o u b l e amount, Connection c o n ) throws SQLException 1 t h i s . accountID = accour~tID; t h i s . c u s t o m e r N a m e = customerName; t h i s . amount = amount; Preparedstatement statement
=

void

null;

try [ statement = c o n . p r e p a r e s t a t e m e n t ( "INSERT INTO ACCOUNT (ACCOUNTID, CUSTOMERNAME, AMOUNT ) " + "VALUES ( ?, 1 , ? ) " ) ; s t a t e m e r ~ t . s e t S t r l n g ( l , accourltID) ; s t a t e m e n t . s e t s t r i n g ( 2 , custornerName) ; s t a t e m e n t . setDouble ( 3 , amount) ; s t a t e m e n t . executelJpdate ( ) ; firlally { if (statement != n u l l ) statement .close ( ) ;

I
I
I

public

v o i d r e a d ( S t r i r 1 g a c c o u r ~ t I D , Corinection c o n ) t h r c ~ w s S Q L E x c e p t i o r j , Reco r d N o t F o u n d E x c e p t i o r t Preparedstatement statement = r ~ u l l ;

try

Capitulo 17
statemertt
=

corl.prepareStatement("SELECT CUSTOMERNAME, AMOUNT


WHERE ACCOUNTID s t a t e m e n t . s e t s t r i n g (1, a c c o u r ~ t I D ) ;
=

FROM ACCOUNT

?") ;

R e s u l t s e t r e s u l t = statement.executeQuery(); i f (result.next 1 ) ) [ t h i s . accountID = accountID; result.getString(1); this.custornerName ; t h i s . amount = r e s u l t . g e t D o u b l e ( 2 ) j else [ t h r o w new R e c u r d N o t F o u n d E x c e p t i o r ~ ( ; i

1
finally { i f (statement != n u l l ) statement .close ( ) ;
[

p u b l i c v o l d u p d a t e ( C n r ~ n e c t l o n curl) t h r o w s PreparedStatement statement = null;

SQLExceptlnn {

try i staternerlt = c o n . p r e p a r e S t a t e m e n t ( "UPDATE ACCOUNT SET CUSTOMERNAME=?, AMOUNT=? WHERE ACCOIJNTID = ? " ) ; s t a t e m e n t . s e t S t r i n g ( 1 , customerName); s t a t e m e n t . s e t D o u b i e (2, a m o u n t ) ; s t a t e m e r ~.ts e t s t r i n g ( 3 , a c c o u n t I D ) ; statement .executeupdate ( ) ; 1 finally { i f (statement != n u l l ) { statement. close ( ) ;

p u b l i c void d e l e t e (Connection con) throws Preparedstatement statement = null;

SQLException

try i statement = c o n . p r e p a r e S t a t e r n e n t ("DELETE F R O M ACCOUNT WHERE ACCOUNTID s t a t e m e n t . s e t s t r i n g ( 1 , a c c o u r ~ t I D; ) . s t a t e r r e n t . executelJpdate ( ) ;

?"I

I
finally [ i f (statement ! = n u l l ) statement.close();
{

I
1

I
~ s t es a la clase de excepci6n que utiliza esta clase de cuenta:
public class RecordNotFoundException exterlds Exception
{

Servicios de contenedor EJB


public

RecordNotFoundException(i

El cliente creari dos cuentas y transferiri dinero entre ellas. Con el primer0 grupo de valores, la transferencia transcurriri con suavidad. Pero si comenta el primer grupo de valores, n o comente el segundo grupo de valores, y ejecuta de nuevo el cliente, se violari una restricci6n durante la transferencia. Desgraciadamente, se ha cargado dinero a la primera cuenta per0 se puede abonar dinero a la segunda cuenta puesto que el balance resultante de la cuenta seri superior a1 valor miximo permitido. Cdando el cliente exista, el banco habri robado dinero del propietario de la cuenta. Aqui esti ese cliente (recuerde incluir el archivo cloudscape . j ar en su ruta de clase cuando ejecute este c6digo):
import import

ja v a . s q l . C o n n e c t i o n ;
j ava. s q l . DriverManager; ss st st st Client1 { atic final atic final a t i c firla1 final final final final

public cla private private private private private private private

S t r i n g ACCOUNT1 = " A 3 2 - 1 1 6 " ; S t r i n g NAMEl = " L y n n e O l d e r " ; d o u b l e AMOTJNTl = 1 0 0 0 0 . 0 ; S t r i n g ACCOUNT2 = " A 3 2 - 1 1 7 " ; S t r i n g NAME2 = " P a t r i c i a M a h a r " ; d o u b l e AMOUNT2 = 1 2 0 0 0 . 0 ; double TRANSFER AMOUNT
=

static static static static

1000.0;

/* * Mary h a s 14000 i n h e r a c c o u n t , t h e r e f o r e * o f 2000 w i l l f a i l t o go t h r o u g h .

credit

* p r i v a t e s t a t i c f i n a l S t r i n g ACCOUNT1 = " B 3 2 - 1 1 6 " ; * p r i v a t e s t a t i c f i n a l S t r i n g NAMEl = " C h r i s t i n a C o u g l i n " ;


private static f i r l a 1 d o u b l e AMOTJNTl
=

10000.0;

* p r i v a t e s t a t i c f i n a l S t r i n g ACCOUNT2 = " B 3 2 - 1 1 7 " ; * p r i v a t e s t a t i c f i n a l S t r i n g NAME2 = " M a r y K l o p o t " ; * p r i v a t e s t a t i c f i n a l d o u b l e AMOUNT2 = 1 4 0 0 0 . 0 ;


* private */
static final double TRANSFER AMOUNT
=

2000.0;

static ( try i C l a s s . f o r N a m e ( " C O M . c l c ~ u d s c a p ec . o r e . JDBCDriver") ;

1 catch

(Exception e ) { System.out.println ( e ) ;

p u b l i c s t a t i c v o i d main(Strir1g[ I a r g s ) { createAccounts(); t r a n s f e r ( ACCOUNTl, ACCOUNT2, TRANSFER AMOUNT) ;

p r i v a t e s t a t i c void createAccounts ( 1 Conr~ection con = n u l l ; try

i
corl
=

DriverManager. getCorlrlectior~(

"jdbc:cloudscape:C:/ProJavaServer/Chl9/tx");
Account account1
=

new A c c o u r ~ (t ) ; AMOUNT1, con);

accountl.create(ACCOUNT1, NAME1,

Capitulo 17

Accourlt a c c o u n t 2 = new Account. ( ) ; a c c o u r l t 2 . c r e a t e (ACCOTJNT2. NAME2, AMOLINT2, S y s t e m . o u t . p r i n t l n ("Acco1ur1ts c r e a t e d . " ) ; catch (Exception e ) { e.printStackTrace ( ) ;

con ) ;

finally { try i i f (con != n u l l ) con. c l o s e ( ) ;

1
]

catch

(Exception e )

1
private static void
=

C o r ~ r ~ e c t i oc no n try

t r a n s f e r ( S t r i n g accour~tIDFrom, S t r i n g accountIDTo, d o u b l e null;

amount)

I
con
=

DriverMar~ager.getCor~r~e~t1or~( " j d b c : c1oudscape:C: /ProJavaServer/Ct119/tx") ;

A c c o u n t a c c o u n t F r o m = new A c c o u n t ( ) ; accountFrom. read (accour~tIDFrom, con) ; A c c o u n t a c c o u n t T o = new A c c o u n t ( ) ; accountTo. read (accour~tIDTo, con); accountFrorn. setAmour~t ( a c c o u r ~ t F r o m . g e t A m ~ ~( u ) r~ -t a m o u n t ) ; a c c o u n t T o . s e t A m o u n t ( a c c o u n t T o . g e t A m o u r ~ (t ) + a m o u n t ) ; a c c o u n t F r o m . u p d a t e (con); accountTo. update (con) ; S y s t e m . o u t . p r i n t l n ( " F u r ~ d st r a n s f e r r e d . " ) ;

1 catch

(Exception e ) i e.printStackTrace ( ) ;

I
firlally { try 1 i f (con ! = n u l l ) con. c l o s e ( ) ;
) {

catch

(Exceptian e )

{ )

El c6digo registra cambios permanentemente en cada etapa hasta que encuentra una excepci6n, ya sea controlada por la 16gica de empresa o por el sistema. En este punto, avanzari ripidamente hasta el final del archivo imprimiendo cualquier mensaje de error y superando el resto de operaciones. En este caso, en el primer ejemplo no debe haber ningfin problema, sin embargo, en el segundo habri una perdida de integridad de datos. ~ s t es a una versi6n perfeccionada del cliente que utiliza transacciones. Cuando la restricci6n de la base de datos es violada y el cliente existe, no se habri extraido dinero de la primera cuenta (es decir, la transacci6n habri sido deshecha) y las cuentas del banco todavia estarin equilibradas:

Servicios de contenedor I3 B
import import. public priv priv priv
j ava. sql. Connection; j ava. s q l . DriverManager;

cla ate ate ate

ss s t s t s t

Clie a t i c a t i c a t i c

nt2 fin fin fin

al al al

S t r i r ~ g ACCOUNT1 = " C 3 2 - 1 1 6 " ; S t r i n g NAME1 = " L a u r e n M a h a r " ; d o u b l e AMOUNT1 = 1 0 0 0 0 . 0 ; S t r i n g ACCOUNT2 = " C 3 2 - 1 1 7 " ; S t r i n g NAME2 = " N i c k O l d e r " ; d o u b l e AMOUNT2 = 1 4 0 0 0 . 0 ; double TRANSFER-AMOUNT
=

private s t a t i c p r i 7 ~ a t es t a t i c pri7iate s t a t i c private s t a t i c t r y


)
1

final final final final

s t a t l c
[

2000.0;

Class.forNarne("COM.cloudscape.core.JOBCUriver");
catch (Exception e ) { System.out.p,sintln(e);

p ~ ~ b l is c t a t i c . ~ r > i s !r n a i n ( S t r i n g [ ] a r g s ) [ c r e a t e A c c o u r % t (s ) ; t r a n s f e r (ACCO1JNT1, ACCOUNT2, TRANSFER-AMOUNT) ;

private s t a t i c void createAccounts ( ) C,jnnection con = null; tr/

1
con
=

DriverManager. getCor,riection( ,,]. d b c : c l o u d s c a p c : C : / F r t ~ J a v a S e r v e r / ~ 7 h l C ) / t x ) ; "

Account a c c o u n t 1 = r~ewAccourlt ( ) ; a c c o u n t l . c r e a t e (ACCOIJNT1, NAME1, AMOUNT1, A c c o u n t a c c o u n t 2 = new Accullr~t ( ) ; a c c o u n t 2 . c r e a t e (ACCOIJNT:, NAME2, AMOIJNT2, S - / s t e m . o ~ u t. p r i n t l n ( " A c c o u n t s catch (Esceptian e ) { e.printStackTrace ( ) ;
{

con);

con);

created.");

finally t r y i i f

( c o n != n u l l ) con.close();

1
1

I
catch ( E s c e p t i a r ~e )
{

1
private s t a t i c > ~ o i dt r a n s f e r ( S t r i n g String con = null; accountIDFrom, accountIDTo, double amount)
{

Connectiorl t r y
[

can

D r i v e r M a n a g e r . g e t C o r ~ r ~ e c t i (o r ~

"jdbc:cloudscape:C:/~roJavaServer/Chl9/tx");

Capitulo 17

A c c o u n t a c c o u n t F r o m = r)ew A c c o u n t ( ) ; a c c o u r t t F r o m . r e a d ( a c c o u n t 1 DFram, c o n ) ; A c c o u n t a c c o u n t T n = new A t ~ c o u r ( ~ 1t ; a c c o u r ~ t T or . e a d ( a c c o u n t I D T o , c o r ~; ) accc.ur,trom..-etArnour1t ( a a : c i i u r ~ t F r o m . q e t A m a ~ r ( t ) - amourlt) ; a c c u u n t T o . s e t A m o u n t ( a c t c o u r l t T o .g e t A m o u r ~ t ( ) + amount) ; a c c c > u n t F r o m .u p d a t e (core) ; a c c n u n t T o . u p d a t e ( c a r , ); System.out . p r i n t l r ~ ("Fur~dstransferred.") ; c o n . cnrnmi t ( ) ;

1 catcl.; try i

(Exception e )

1 catch

con. r o l l b a c k ( ); (Exception r e ) e.printStackTrace0;

{I

finally { try i i f (con != r11~1l1 ) con. c l o s e I ) ;


1

1 catch

(Exception e )

1t

Una ventaja de permitir que el contenedor EJB gestione transacciones por nosotros consiste en que podemos desarrollar componentes sin preocuparnos por cuindo debemos realizar o deshacer una transaccibn. En cierto sentido, un contenedor EJB actua como lo hace el cliente en este ejemplo, averiguando cuindo comienza la logica de empresa y cuindo termina y gestionando transacciones consecuentemente. Lo hace examinado 10s atributos transaccionales de 10s mitodos EJB que declaramos en el descriptor de implementaci6n. Antes y despues de cada metodo de empresa, garantiza que se inicia, o se deshace, cualquier transacci6n necesaria. Por supuesto, es bastante ficil ariadir gesti6n de transacci6n para este sencillo caso. En una aplicaci6n rnis complicada, con muchas posibles secuencias de metodo, excepciones de aplicaci6n y tipos de objetos de empresa, resulta rnis dificil mantener todos 10s balones en el aire. N o es necesariamente imposible, pero, ciertamente, es mucho rnis dificil. La dificultad aumenta por 6rdenes de magnitud para una transacci6n distribuida, es decir, cuando hay rnis de una base de datos que esti siendo actualizada. Si de la cuenta de la que se extrae dinero y la cuenta en la que debe ingresarse se encuentran en diferentes bases de datos, ya no es posible que el programador de la en su lugar, aplicacion utilice las sencillas capacidades transaccionales de la clase j ava .sql .Connection. debemos gestionar un complicado proceso conocido como "realizaci6n'en dos fases". Una realization en dos fases, como ya hemos visto, implica a un gestor de transacciones sometidas a XA que analiza la capacidad de 10s recursos para realizar cambios y les indica despues que sigan adelante si todos 10s recursos alistados deciden realizar la acci6n. La implementaci6n de este proceso es muy complicada y propensa a errores, y 10s detalles especificos van rnis alli del alcance de este libro. Nuestro contenedor EJB puede gestionar esta complejidad por nosotros (algunos n o lo hacen), aunque esto no se requiere como parte de la especificaci6n EJB. Si no lo hace, y necesitamos seriamente esta funcionalidad, debemos encontrar un servidor de aplicaci6n diferente, ya no existe ningun rodeo. Una transaction distribuida tambien necesita la colaboraci6n de drivers JDBC.

Servicios de contenedor EJB


U n driver JDBC que participa en una transacci6n distribuida debe implementar una interfaz especial que el gestor de transacci6n utilizari para comunicar con 61 durante la transacci6n. Esta interfaz es un estindar industrial y se conoce como XA, la versi6n Java de que se define como parte del Paquete Opcional JDBC. Observe que XA en realidad hace referencia a TransAction, aunque es dificil saber por qu6. Antes de utilizar un controlador JDBC en una transacci6n distribuida, debemos asegurarnos que es compatible con la interfaz XA. En la actualidad, todos 10s controladores que se ajustan a JDBC 2.0 se adaptan a la gestidn de transacciones distribuidas. Existe una lista de controladores JDBC que se adaptan a transacciones distribuidas en el sitio Web de Sun en http://industry.java.sun.com/products/jdbc/drivers.

Sernantica declarativa para transacciones


El desarrollador de bean debe declarar c6mo funciona un metodo concreto en un EJB con transacciones gestionadas por contenedor con esas transacciones, especificando una etiqueta <t rans-att ribute> en el descriptor de implementaci6n XML. La especificaci6n EJB ofrece seis opciones: Not Supported, Supports, RequiresNew, Required,Mandat ory y Never. Examinemos mas de cerca estas opciones de atributos transaccionales.
El atributo transaccional Notsupported

La primera opcibn para un atributo transaccional de metodo es Not Supported. Cuando se invoca un metodo con un atributo de transacci6n Not Supported, opera en una "contexto de transacci6n no especificado". (Un contexto de transacci6n es sencillamente el estado que necesita mantenerse de mod0 que el conjunto de operaciones relacionadas pueda operar como un grupo.) La especificacion da a1 contenedor EJB gran libertad para acceder a recursos en el caso de un contexto de transacci6n no especificada. Las posibles formas de acceder a estos recursos, como sugiere (pero no obliga) la especificacidn EJB 2.0 son: El contenedor puede ejecutar el metodo y acceder a 10s gestores subyacentes de recursos sin un contexto de transacci6n. Recuerde que "gestor de recursos" es el tkrmino generic0 para cualquier clase de comtrolador Java o almacen que interactue con un factor en el entorno de ejecuci6n. Por ejemplo, una instancia j ava . sql .Connection es un gestor de recursos para una base de datos. O t r o ejemplo de gestor de recursos es una conexi6n JMS, j avax .j m s .Connection. El contenedor puede tratar cada llamada de una instancia a un eestor de recursos como una unica transacci6n (por ejemplo, el contenedor podria configurar la opcibn auto-realizar en una conexi6n API JDBC).
u

El contenedor puede fusionar multiples llamadas de una instancia a un gestor de recursos en una sola transaction. El contenedor puede fusionar multiples llamadas de una instancia a multiples gestores de recursos en una sola transacci6n. Si una instancia invoca metodos sobre otros beans de empresa y 10s mitodos invocados son tambien designados para ser ejecutados con un contexto de transacci6n no especificado, el contenedor puede fusionar 1as llamadas del gestor de recursos procedentes de multiples instancias en una sola transaccibn. Cualquier combination de las anteriores. Siempre que un mitodo de empresa se ejecuta fuera de una transacci6n especificada en la aplicacibn, existe el peligro de que el recurso a1 que accede ese metodo de empresa se convierta en inconsistente. La variedad de tknicas que puede utilizar el contenedor EJB en este caso indica iqcluso mis claramente cuinta precauci6n debemos Ilevar, y como de conservadora debe ser la programacibn del desarrollador.

Capitulo 17
Si un metodo con un atributo N o t s u p p o r t e d es invocado por otro metodo con un contexto transaccional especificado, el contenedor EJB suspenderi esta transacci6n mientras se ejecuta el metodo con el atributo N o t s u p p o r t e d . Nunca se pasa un contexto de transacci6n a un cliente o un recurso procedente de un metodo de empresa con el atributo N o t S u p p o r t e d . Sin embargo, una vez vuelve el metodo, se reinicia cualquier transaccibn que haya sido suspendida.

El atributo transaccional RequiresNew


El atributo transaccional R e q u i r e s N e w para un metodo especifica que, si se invoca un mitodo con este atributo con un contexto de transacci6n existente, el contenedor suspended esa transacci6n e iniciari una nueva. Esta nueva transacci6n se utilizari para cualquier acceso a recursos u otras llamadas de metodo de empresa desde ese metodo. Sin embargo, una vez concluido el metodo, cualquier transacci6n suspendida seri retomada. Si el metodo es invocado sin una transacci6n existente, tambien se creari una nueva. La transacci6n se realizari cuando el metodo vuelva y el EJB haya completado sus tareas "domisticas" (como devolver 10s beans a las reservas, liberar recursos asipados durante la operacibn, etc.)

El atributo transaccional Required


Si un atributo transaccional de metodo es R e q u i r e d , el contenedor EJB siempre invocari este metodo con un contexto de transacci6n vilido. Si el metodo es invocado desde un cliente (por ejemplo, otro bean) con un contexto de transacci6n existente, se utilizari ese contexto. Si el metodo es invocado sin un contexto de transacci6n existente, el contenedor EJB creari uno automiticamente. En este caso, la transacci6n se realizari despuis de que el metodo vuelva y de que el contenedor EJB haya completado sus tareas, como invocar e j bS t o r e ( ) .

El atributo transaccional Supports


Si un metodo con el atributo transaccional s u p p o r t s es invocado por el cliente con uncontexto de transacci6n vilido, el contenedor actua igual que si el atributo transaccional fuera R e q u i r e d . Si el metodo es invocado sin un contexto de transacci6n existente, el contenedor actuari igual que si el atributo transaccional fuera N o t S u p p o r t e d . En otras palabras, el desarrollador de componente EJB debe estar preparado para cualquiera de las dos situaciones: ejecuci6n transaccional o no-transaccional.

El atributo transaccional Mandatory


Si un metodo con el atributo transaccional M a n d a t o r y es invocado con un contexto de transacci6n existente, el contenedor utilizari ese contexto. Si se invoca un metodo con este atributo sin un contexto de transacci6n existente vilido, el contenedor genera una excepci6n (javax.Transaction.TransactionRequiredException).

atributo transaccional Never


La opci6n final para un atributo transaccional de metodo es N e v e r . Si un cliente invoca con un contexto de transacci6n existente, el contenedor genera una excepci6n ( j a v a r m i R e m o t e E x c e p t i o n ) . El cliente debe invocar sin un contexto de transacci6n, en cuyo caso el contenedor se comporta como en el caso d e ~ o t ~ u p p o r t e d .

Especlficar atributos transaccionales


Los atributos transaccionales para un metodo son especificados en el descriptor de implementaci6n XML, que utiliza elementos < c o n t a i n e r - t r a n s a c t i o n > para indicar 10s atributos de transacci6n que se aplican a 10s diversos mktodos. Cada elemento < c o n t a i n e r - t r a n s a c t i o n > tiene dos elementos secundarios: un metodo y el atributo transaccional. Existen tres formas legales de especificar el elemento de metodo.

Servicios de contenedor J B
El primer mod0 consiste en especificar un atributo de transacci6n por defecto para todos 10s mktodos en un bean determinado. Este atributo por defecto so10 se aplicaria si no hubiera un atributo de transaccih mis especifico en el descriptor (especificado por uno de 10s dos siguientes mktodos). U n ejemplo:

El elemento < e j b-name> hace referencia a1 nombre de uno de 10s EJB declarados en ese mismo descriptor de implernentacion. El simbolo * en el elemento <method-name> es un "comodin" que indica que el atributo de transaccion debe aplicarse a todos 10s mktodos. El segundo mod0 consiste en especificar un atributo de transacci6n para mitodos de un bean concreto, por ejemplo:

Si hay mktodos con el mismo nombre pero diferentes listados de parimetros y requieren diferentes atributos de transacciones, puede utilizarse este tercer mitodo que especifica 10s parimetros:

Para configurar el atributo de transacci6n para un mktodo sin parimetros, utilice el elemento <methodpa rams> sin ningun elemento secundario <method-param>.Si se pasa una matriz como parimetro, puede ser especificado por el tip0 de elementos de la matriz, seguido por uno o mis pares de corchetes.

Elegir atributos de transaccion


i C u i l de 10s atributos de transacci6n disponibles debemos utilizar? Esto dependeri de 10s requisitos de nuestros mktodos de empresa para las propiedades ACID (recuerde: atomico, consistente, aislado y duradero). Tambikn dependeri de la compatibilidad con transacciones proporcionadas por nuestros recursos persistentes:

LI Si tenemos un mktodo que modifica datos en una base de datos relational, seguramente querremos
que participe en una transacci6n. Sin embargo, probablemente no tendriamos ninguna circunstancia especial que requiriera una nueva transaccih. El mejor atributo probablemente seria
Required.

Capitulo 1 7
0 Si tuvikramos un metodo de empresa que recuperara un finico fragment0 de datos, no necesariamente tendriamos circunstancias que requirieran que gestioniramos una transacci6n y podriamos dejar la determinaci6n en manos del contenedor EJB. Sin embargo, si este acceso a datos tiene lugar en el context0 de otra operaci6n que ha modificado datos, querriamos tener una . vlsta consistente de la base de datos. El atributo que permitiria estas dos cosas es S u p p o r t s . 0 Si el recurso al que accede nuestro bean de empresa no es compatible con la gestion por parte de un coordinador de transacci6n externo, debemos utilizar el atributo N o t S u p p o r t e d para todos 10s metodos del bean.

Los restantes atributos transaccionales son mis oscuros per0 otorgan a1 servicio de transaccion declarativa del contenedor la capacidad de gestionar la mayor parte de las situaciones. Los metodos e j bLoad ( ) y e j b S t o r e ( ) de retrollamada de persistencia de un bean de entidad son invocados con 10s mismo atributos transaccionales que el metodo de empresa que ha desencadenado e j bLoad ( ) o e j b S t o r e ( ) . Esto tiene sentido ya que 10s atributos transaccionales de un metodo de empresa se relacionan principalmente con 10s recursos a 10s que accede el metodo de empresa, ya sea directamente (a traves de llamadas SQL, por ejemplo) o indirectamente, a traves de la lbgica de lectura y actuahaci6n de un bean o un contenedor asociado a esos metodos de retrollamada. El metodo e j b s t o r e ( ) tambien garantiza su invocaci6n en el limite de realizaci6n de la transaccion. Sin embargo, la situacion es mis complicada en 10s casos en 10s que el metodo de empresa es invocado sin una transaccion, lo cual puede suceder con 10s atributos de transaccion Not S u p p o r t e d , Never o S u p p o r t s . La gesti6n de almacenamiento en cache del estado del contenedor EJB funciona bien solo si el contenedor puede utilizar limites de transacci6n para controlar 10s metodos e j bLoad ( ) y e j bS t o r e ( ) . Solo hay dos garantias establecidas por la especificacion sobre el momento de invocaci6n de estos metodos de retrollamada para un metodo de empresa que opera fuera de una transaccion:
O El contenedor invoca e j bLoad ( ) a1 menos una vez entre el momento en que el EJB se asocia por

primera vez con una identidad de objeto y el momento en que se invoca el metodo de empresa. Observe que esta asociacion con una identidad esti marcada con la retrollamada e j bAct i v a t e ( )

El contenedor invoca e j b s t o r e ( ) a1 menos una vez entre el momento en que se invoca el metodo de empresa y el momento en que el EJB se disocia de una identidad de objeto. Observe que esta disociaci6n de una identidad esti marcada por la retrollamada e j b P a s s i v a t e ( ) . Las garantias dadas por la especificacion en cuanto a1 momento de invocaci6n de e j bLoad ( ) y e j b s t o r e ( ) no son suficientes para apoyar el almacenamiento en cache del estado. En el period0 de tiempo entre la invocation de e j bLoad ( ) y la ejecuci6n del metodo de empresa, 10s datos del almacen de datos persistente pueden haber cambiado y el EJB podria potencialmente estar operando sobre datos desfasados. Por supuesto, si el EJB tiene acceso exclusive a la base de datos, o si 10s datos no tienen requisitos absolutes de renovacion, este problema puede resolverse.

El problema mis grave es que, entre el momento en que se ejecuta el metodo de empresa y la invocaci6n de e j b ~o rt e ( ) por parte del contenedor, puede haberle sucedido algo a1 EJB que haya provocado que 10s datos en cache desparezcan sin haber sido nunca escritos en la base de datos. Por ejemplo, un metodo de empresa posterior podria causar un error en el EJB que fuerce a1 servidor de la aplicacibn a expulsar esa instancia de bean del contenedor. Incluso es posible que el contenedor EJB pudiera fallar. El cliente asumiria que 10s cambios de sus datos han sido efectuados con exito, porque el mCtodo de empresa el metodo de empresa invocado no habia devuelto ningfin error. Pero, en realidad, 10s recursos subyacentes nunca serian actualizados. La soluci6n al problema de acceso a datos no-transaccionales consiste en evitar utilizar e j bLoad ( ) y e j b s t o r e ( ) para controlar el almacenamiento en cache de estado en el EJB. Habitualmente, el metodo de empresa accede directamente a1 estado del recurso subyacente (a traves de instrucciones SQL, por ejemplo) y 10s metodos de retrollamada e j bLoad ( ) y e j b S t o r e ( ) deben quedar vacios. Sin embargo, si

Servicios de contenedor EIB


10s rnetodos del bean son de s61o lectura y tiene acceso exclusive a la base de datos o n o necesita datos totalmente renovados, probablemente podemos guardar en cache el estado en un bean no-transaccional corno hacemos norrnalrnente. En otras palabras, podernos implementar e j b L o a d ( ) pero e j b s t o r e ( ) todavia debe quedar corno no-operativo puesto que nuestro bean s610 lee 10s datos y no 10s rnodifica. Para resumir, el almacenarniento en cache de datos con e j b L o a d ( ) es una soluci6n apropiada en 10s siguientes casos: Para representar datos no-transaccionales corno una entidad EJB

o Para evitar lecturas repetidas de estos datos


Si n o necesitarnos actualizar 10s datos
0

Si nos interesa que 10s datos en cache abandonen la sincronizacion del alrnacen persistente

Transacciones controladas por el usuario


Es posible que un bean de sesion controle su propia demarcaci6n de transacci6n, a traves de la interfaz j a v a x . T r a n s a c t i o n . U s e r I n t e r f a c e . Lainterfaz~ser~ransactionsedefineasi:
public interface UserTransaction { public void begin() throws NotSupportedException, SystemException;

public void commit ( ) throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, IllegalStateException, SystemException; public int getstatus() throws SystemException;

public void rollback 0 throws IllegalStateException, SecurityException, SystemException; public void setRollbackOnly ( ) throws IllegalStateException, SystemException; public void setTransactionTimeout (int timeout) throws SystemException;

Brevemente, un cliente o un bean de sesi6n invoca el metodo b e g i n ( ) para iniciar programiticamente una transacci6n. Esta transacci6n puede concluir con exit0 invocando c o m m i t ( ) o sin exit0 invocando r o l l b a c k ( ) . En lugar de deshacer sirnplernente una transacci6n, un rnktodo de ernpresa puede tambien marcar la transacci6n de rnodo que el h i c o resultado sea una anulaci6n. Esto tendria sentido si pudieran invocarse mktodos posteriores que deben forrnar parte de esta transacci6n. El metodo g e t s t a t u s ( ) puede ser utilizado para deterrninar si la transacci6n ha sido rnarcada para ser deshecha o anulada. N o se requiere un contenedor EJB o un servidor de aplicaci6n J2EE adaptable para poner la interfaz U s e r T r a n s a c t i o n a disposici6n de todos 10s clientes. Sin embargo, debe estar disponible para beans de sesion, sewlets y JSP y, opcionalmente, para otro tipo de clientes (corno clientes Java aut6nomos) y seguir siendo adaptable. Un cliente que desea utilizar esta interfaz debe recuperarla del espacio de nombre J N D I . Una irnplernentaci6n adecuada de la interfazus e r T r a n s a c t i o n estari disponible bajo el nombre

Capitulo 17
java : comp. /~ser~ransaction. Es conveniente destacar que 10s beans de sesibn tambikn pueden n metodo : utilizar un mitodo de legado para recuperar la i n t e r f a z ~ s e r ~ r a n s a c t i oel SessionContext.
Para marcar el inicio de una transaccion, el cliente (un bean de sesibn, un servlet, una pigina JSP u otro elemento) invoca el mitodo begin ( ) y, para marcar el final efectivo de una transaccion, invoca commit 0. Considere el caso en el que un servlet quiere invocar 10s mktodos de empresa en dos beans diferentes como parte de la misma transaccibn. Asuma 10s siguientes mitodos de empresa de bean de sesi6n:
public class SarnpleSessionA implements
( )

SessionBean

public

// //

v o i d someBusinessMethod algunas retrollamadas de 16gica de empresa,

...

etc.

public

class

SampleSessionB implements
)

SessionBean

p u b l i c void otherBusinessMethod ( / / o t r a s retrollamadas

I
//
1

...

de

16gica de

empresa,

etc.

Suponiendo que estamos utilizando un servidor de aplicaci6n JZEE, el servlet podria tener un c6digo parecido a iste:

UserTransaction userTransaction = ( U s e r T r a n s a c t i o n ) i n i t i a l . lookup("java:comp/UserTrar~sactior~"); S a m p l e S e s s i o n A H o m e homeA = ( S a m p l e S e s s i o n A H o r n e ) j a v a x . r m i . PortableRemoteObject.r~arrow( i n i t i a l . lookup("java:comp/er~v/ejb/SampleA"), S a m p l e S e s s i o r ~ A H o m e . c l a s s ) ; SampleSessionA sampleSessionA


=

homeA. c r e a t e ( ) ;

SampleSessionB sampleSessionB

homel3. c r e a t e ( 1 ;

userTransaction. commit ( ) ;
}
I

catch (Exception e ) 1 userTransaction. rollback (Exception e )


{

( ) ;

catch

Servicios de contenedor EJB

U n inconveniente de este enfoque es que el cliente adopta la responsabilidad de gestionar la transaccibn, en lugar de dejarla en manos de contenedor EJB. U n segundo inconveniente es que 10s cambios de la estrategia de gesti6n de transacci6n deben ser efectuados en el c6digo Java, en lugar de en un archivo XML utilizando una herramienta. Observe que el ejemplo anterior, se podria haber conseguido el mismo efecto definiendo un nuevo metodo de bean de sesi6n con un atributo de transacci6n R e q u i r e d . El servlet podria invocar el nuevo metodo de bean de sesi6n y ese nuevo metodo de bean de sesi6n invocaria entonces s o m e B u s i n e s s M e t h o d ( ) y o t h e r B u s i n e s s M e t h o d ( ) . Entonces, no seria necesario en absoluto utilizar IainterfazlJserTrans a c t i o n .

Niveles de aislamiento
Mantener una transaccidn aislada de 10s efectos de otras transacciones con 10s mismo datos puede resultar una operaci6n cara. Para muchas situaciones, el aislamiento no-perfecto es aceptable en terminos de 16gica de empresa y puede producir una aumento significativo del rendimiento y una disminuci6n del potential para bloqueos entre transacciones conflictivas. La mayoria de bases de datos multi-usuario ofrecen algo de apoyo para realizar concesiones en aislamiento versus rendimiento y JDBC proporcionar una interfaz estindar para controlar esta funcionalidad.

La especificaci6n EJB no es especifica de bases de datos relacionales; intenta ser una tecnologia de objetivo general que resulte Gtil para acceder a diferentes recursos, como sistemas ERP, sistemas de gesti6n de ventas, bases de datos de objeto, bases de datos relacionales y otros. Los API para gestionar niveles de aislamiento con especificos de recursos y por ello la arquitectura EJB no define un API general para gestionar el nivel de aislamiento de transacciones. A pesar de todo, esta gestion puede ser importante para un sistema de producci6n de gran escala o para un sistema con requisitos muy estrictos de correccidn de datos.
Los EJB que gestionan su propio acceso a recursos, como beans de sesi6n o beans de entidad con persistencia gestionada por bean, pueden especificar programiticamente el nivel de aislamiento de esos recursos. JDBC proporciona dos mktodos en la interfaz j a v a .s q l . C o n n e c t i o n para configurar y obtener el nivel de aislamiento:
void setTransactionIsolation(int level) throws SQLException; int getTransactionIsolation() throws SQLException;

Es probable que un desarrollador EJB conozca la base o bases de datos de destino y sea capaz de determinar un nivel apropiado de aislamiento consultando la documentaci6n de la base de datos. Sin embargo, tambikn es posible descubrir programiticamente si se puede o no configurar un determinado nivel de aislamiento para la fuente de datos referenciada por una conexi6n particular invocando el metodo g e t M e t a D a t a ( ) de l a i n t e r f a z c o n n e c t i o n . Esto devuelveun objeto que implementalaidterfaz D a t a b a s e M e t a D a t a . Hay dos mktodos relevantes en esta interfaz:
int getDefaultTransactionIsolation~) throws SQLException; boolean supportsTransactionIsolationLevel(int level) throws SQLException;

El primer0 devuelve el nivel de aislamiento por defect0 que utiliza el recurso dentro de una transacci6n y el segundo indica si el recurso apoya un nivel de aislamiento con caracteristicas concretas. Los EJB que dependen del contenedor para mediar el acceso a sus recursos (0, en otras palabras, beans de entidad con persistencia gestionada por contenedor) no gestionan ellos mismos 10s niveles de aislamiento. Sin embargo, el contenedor EJB puede proporcionar mecanismos de propiedad para permitir a1 implementador ajustar niveles de aislamiento cuando se implementa la aplicaci6n.

Capitulo 17
Independientemente de que sea el EJB o el contenedor quien gestiona 10s niveles de aislamiento, debemos llevar cuidado para que todos 10s accesos a una determinada base de datos u otro recurso dentro de una hnica transacci6n utilicen el mismo nivel de aislamiento. En otras palabras, un bean A no puede realizar una SELECCION utilizando un nivel de aislamiento despuk de que un bean B haya realizado una ACTUALIZACION en la misma transacci6n utilizando un nivel de aislamiento diferentes. Si un EJB accede a mis de un recurso en una transacci6n, cada recurso puede utilizar un nivel de aislamiento diferente.

Te'cnicarnente, el requisito para utilizar u n nivel consistente de aislamiento para u n determinado recurso dentro de una transaccidn es establecido pov el vecurso, no por la cspccifrcacidrr EJB, La mayoria de 10s recursos requieren que todos 10s accesos dentro de una transaccio'n se realicen utilizando 10s mismos niveles de aislamiento. U n intento de cambiar el nivel de aislamiento en medio de una transaccidn puede provocar u n comportamiento no deseado, como una realizacidn implicita de 10s cambios efectuados basta ese momento. La interfaz j a va . sql . Connect ion prohibe especi$camente cambiar u n nivel de aislamiento en medio de una transaccidn. Si esto no se aplica a u n determinado recurso que este' utilizando, aprove'chelo si puede y si 10s requisitos de su aplicacidn justif;;can la complejidad adicional (lo cual es bastante poco probable).
U n recurso como una base de datos puede definir grados arbitrarios de aislamiento con 10s que puede operar una transacci6n. Sin embargo, la interfaz j a v a . s q l . C o n n e c t i o n opera con cuatro niveles de aislamiento predefinidos (son constantes de n h e r o enteros definidas en la clase c o n n e c t i o n ) :

O TRANSACTION-READ-COMMITTED O TRANSACTION-REPEATABLE-READ
O TRANSACTION-SERIALIZABLE Estas constantes hacen referencia a niveles especificos de aislamiento de transacci6n que se enfrentan a tres problemas bien definidos de creciente dificultad: "lecturas sucias", "lecturas no repetiblesny "lecturas fantasma". Definamos estos terminos con mis detalle: Una lectura sucia permite que una fila cambiada por una transacci6n sea leida por otra transacci6n antes de que haya realizado cualquier carnbio en la fila. Configurar un nivel de aislamiento que permita tanta interferencia es bastante permisivo y, aunque puede mejorar el rendirniento, resulta a menudo inapropiado desde el punto de vista del rnantenimiento de la integridad de datos. Tome un ejemplo de una transferencia de balance de cuenta y una retirada de dinero desde un cajero automitico sirnultineas. U n usuario de nuestro software intenta transferir fondos desde una cuenta de ahorros a una cuenta corriente. A1 rnismo tiempo, la esposa del usuario intenta retirar dinero desde un cajero automitico. Pongamos que la operaci6n de transferencia falla despues de haber incrementado la cuenta corriente, de modo que la operaci6n sea anulada por la base de datos. Sin embargo, si el nivel actual de aislamiento para la retirada de dinero del cajero automitico permite lecturas sucias, puede haber leido 10s datos de transferencia de balance no realizada y haber permitido que la retirada de dinero se haya realizado con kxito, incluso si no habia dinero suficiente en la cuenta.
0

Una lectura no repetible es aquella en la que una transacci6n lee una fila, una segunda transacci6n altera o elimina la fila y la primera transaccion vuelve a leer la fila, obteniendo diferentes valores la segunda vez. El modo exacto de evitar esto depende de nuestra base de datos y puede influir en nuestra eleccion de configuraciones de aislamiento. Puede suceder que las actualizaciones realizadas a datos relevantes Sean impedidas por un nivel de aislamiento que garantiza las lecturas repetibles o puede suceder que las actualizaciones a datos relevantes sean ocultadas por este nivel de aislamiento. El punto mis irnportante a destacar es que debemos siempre comprender la base de datos en la que estamos implementando, si esto es relevante para nuestra aplicaci6n.

Servicios de contenedor EJB


0 Una lectura fantasma es aquella en la que una transacci6n lee todas las filas que satisfacen una

condici6n WHERE, una segunda transacci6n inserta una fila que satisface la condici6n WHERE y la primera transaccibn vuelve a leer la misma condition, recuperando la fila fantasma adicional en la segunda lectura. De nuevo, la influencia exacta que tiene este nivel de aislamiento depende de c6mo implemente nuestra base de datos el nivel de aislamiento, ya sea bloqueando u ocultando 10s cambios (probablemente realizando copias de 10s datos). Una vez mas, debemos entender la base de datos en la que estamos implementando. Cada nivel de aislamiento evita un conjunto diferente de problemas. El nivel de aislamiento mis permisivo, TRANSACTION-READ-UNCOMMITTED, n o evita en realidad ninguno de ellos. Debemos ser cautos con este nivel de aislamiento. Es adecuado en situaciones en las que la integridad absoluta de 10s datos es una prioridad inferior a1 rendimiento. U n ejemplo podria ser un sitio de comercio electr6nico que estuviera ofreciendo recomendaciones a 10s compradores basindose en patrones de compra de otros visitantes del sitio. Seria importante responder con rapidez, para evitar que un comprador se irrite o se marche, pero podria no ser importante tener un conjunto preciso de recomendaciones. evita lecturas sucias, pero permite lecturas no El nivel de aislamientoTRAN~A~T10~-READ-COMMITTED repetibles y fantasma. Aunque cualquier decision sobre niveles de aislamiento debe tener en cuenta requisitos de integridad de datos de la aplicacion, la base de datos de destino y las necesidades de rendimiento y reajustabilidad, una sencilla recomendacih genirica para muchas situaciones es utilizar este nivel de aislamiento. evita las lecturas sucias y las lecturas n o El nivel de aislamientoTRAN~A~~10~-REPEATABLE-READ repetibles. Las lecturas fantasmas no se evitan. El nivel de aislamientoTRANSACTION-SERIALIZABLE evita las lecturas sucias, no repetibles y fantasma. ~ s t es e un nivel de aislamiento muy restrictivo, que, aunque afectaria probablemente a1 rendimiento, garantizaria resultados correctos. La siguiente tabla resume 10s diferentes niveles de aislamiento disponible a travis del API JDBC: Nivel de aislamiento
TRANSACTION-READ-UNCOMMITTED TRANSACTION-READ-COMMITTED TRANSACTION-REPEATABLE-READ
TRANSACTION-SERIALIZABLE

I1

Problemas evitados Ninguno Lectura sucia Lectura sucia Lectura no repetible Lectura sucia Lectura no repetible Lectura fantasma

Transacciones largas
La tecnologia EJB, junto a las capacidades de recurso transaccional, puede garantizar que nuestra Iogica de empresa opera con las ventajas de una transaccibn. Pero mantener una transaccion resulta caro, principalmente debido a1 b!oque_o y/o copia que debe llevar a cab0 un recurso de datos para garantizar que se aplican las propiedades A C I D de una transaccion. Como resultado, las transacciones deben mantenerse cortas. Eso significa que 10s datos deben ser leidos, actualizados y escritos en una operaci6n 16gica. Por desgracia, la realidad de la mayoria de aplicaciones es que 10s datos serin leidos, presentados a1 usuario, editados, enviados de vuelta a1 senidor y escritos a la base de datos. En un mundo perfecto con

Capitulo 1 7
recursos ilimitados y ningun tip0 de contenci6n para 10s datos, todo esto tendria lugar en una transacci6n. Pero el usuario puede trabajar con estos datos durante un period0 de tiempo arbitrariamente largo. Imagine una situaci6n en la que un usuario abre una aplicacion, empieza a editar algunos datos y se marcha para unas vacaciones de tres semanas sin realizar sus cambios a la base de datos. N o resulta apropiado normalmente dejar una transacci6n abierta a lo largo de cualquier acci6n de interfaz de usuario. i C 6 m o podriamos incluso dejar una transacci6n abierta? Utilizando transacciones gestionadas por contenedor, no es posible. Sin embargo, podemos dejar una transaccicin abierta durante llamadas de metodo de empresa utilizando la interfaz U s e r T r a n s a c t i o n analizado anteriormente. Por ejemplo, - durante un metodo de empresa, podriamos adquirir la interfaz U s e r T r a n s a c t i o n y comenzar la transaccion. Durante un metodo de empresa posterior, volveriamos a adquirir U s e r T r a n s a c t i o n y continuariamos autorniticamente esa transaccion. Todos 10s demis metodos de empresa en ese bean de Observe que esto s610 sesion tendrian lugar en la misma transacci6n hasta que invociramos commit 0. es posible para beans de sesion con estado. U n bean de sesi6n sin estado debe realizar la transacci6n antes de vuelva el metodo de empresa en que fue iniciado. Si no es asi, la transaccion se pierde y nunca se realizari. Eventualmente, caducari. ~ s t podria e ser el aspect0 del c6digo para una transacci6n que siguiera abierta entre metodos de empresa:
c l a s s L o n g T ~ - a r ~ s a c t i o r 1 S e s s i o r 1 B e ai rm 1 plements S e s s i ~ n B e a n { p u b l i c vcmid m e t h i d l ( ) t h r o w s E x c e p t i o n 1 UserTransaction iunerTransaction = ( U s e r T r a n s a c t i o r i ) i r ~ i t i a l1 .ookupi"j ava: comp/UserTrar~saction") ; u s e r T r a n s a c t i n n . begin() ;

p u b l i c v ~ i dmethod: ( ) t h r o w s perfol-mBusinessLogic2 ( ) ;

Exceptior!

1
p ~ u b l i c v o i d meth':~d3() throws performBusinessLogic3 ( ) ; Excepti~n{

UserTransaction userTransaction = (Use~Trar~sactior i~ r~ ) i t i a l l.o o k u p ( " j a v a : c o m p / U s e r T r a r ~ s a c t i o r ~ ; ") u s e r T r a r ~ s a c t i o n . c o m r r i i t( ) ;

1
//
I

. ..

rnetodos

de

retrollamada,

etc.

En general, no aproveche la ventaja de la capacidad de utilizar una unica transacci6n en multiples llamadas de metodo de empresa. En cambio, debemos utilizar estrategias especificas de aplicaci6n que sean mis conservadoras de recursos para conseguir un efecto similar en una transacci6n. Los dos principales enfoques son implementaciones de bloqueo optimista o bloqueo pesimista.

Bloqueo optimista
La estrategia de bloqueo optimista permite a multiples clientes utilizar 10s mismos datos. Sin embargo, cuando 10s datos son enviados de vuelta a1 servidor en llamadas de metodo de empresa de un EJB, se realiza cierta comprobaci6n para garantizar que 10s datos de estado de un EJB pueden ser actualizados sin problema. Por ejemplo, el momento de la ultima modificaci6n puede compararse con el momento en que el cliente retir6 10s datos por primera vez. Si coinciden, la actualizacibn tiene permiso para proceder. Si no coinciden, se notifica a1 cliente que debe renovar 10s datos y rehacer las modificaciones. Algunas formas posibles de implementar esta estrategia son:

Servicios de contenedor EJB


0 Afiadir un campo de estampilla de tiempo de la ultima modification a la base de datos 0 Antes de enviar la consulta de actualization, comparar loa valores que estin a punto de ser modificados con su valor anterior a1 inicio de la transaccion. Si son iguales, la actualizacion es segura. Si son diferentes, la actualizaci6n alterari la base de datos y la transaccion debe anularse.

Bloqueo pesimista
La estrategia pesimista es la mis reajustable porque multiples clientes pueden leer 10s datos sin interferir con una cliente individual que desea actualizar. Sin embargo, si una actualizacion conlleva mucho trabajo, puede resultar inapropiado indicar a un segundo cliente que debe descartar este trabajo porque alguien e s t i realizando una modificacidn. En este caso, puede utilizarse un enfoque de bloqueo pesimista. U n cliente que quiere realizar modificaciones debe "comprobarUsu derecho a modificar datos. Mientras que comprueba esta sefial, ningun otro cliente puede modificar 10s datos. Si otro cliente ha comprobado el derecho a modificar 10s datos, se genera una excepcion. Una posible forma de implementar esta estrategia consiste en afiadir un campo de comprobacion de tiempo a la base de datos. Si este campo es nulo, la comprobacion puede tener ixito, basandose en cuinto tiempo puede un cliente mantener 10s datos comprobados antes de que expire el bloqueo.

Realization en dos fases


C o m o hemos analizado anteriormente, una realization en dos fases es un protocolo que permite a multiples gestores detransaccidn participar en una unica transaccion. Hay dos situaciones en las que esto sucederi:
0 0

La logica de aplicacion accede a multiples recursos (como dos bases de datos) dentro de una Gnica transaccion EJB en multiples senidores de aplicacidn participan en la misma transaccion

Cualquiera de estas situaciones es bastante probable en una empresa con sistemas informiticos transaccionales heterogineos. Es ficil imaginar una aplicacidn que necesite actualizar una base de datos de ventas y una base de datos de fabrication que sea mantenida en dos equipos diferentes. Tambiin es ficil imaginar dos senidores de aplicacion ejecutados en diferentes departamentos, con la necesidad de utilizar 16gica comun. U n programador de bgica de empresa no necesita escribir cddigo especial para manejar una situacidn en la que tenga lugar una realization de dos fases: la carga de implementar gesti6n de transaccion recae segun la especificacion EJB sobre el contenedor EJB y el servidor de aplicacidn. Sin embargo, debido a que no todos 10s controladores JDBC y servidores de aplicacion son compatibles con realizaciones en dos fases, el arquitecto de la aplicacion necesita ser consciente de situaciones en las que esto puede suceder y de las ~imiticiones de la t&nologia. Observe que, para realizaciones de dos fases, un controlador necesita ajustarse a 10s API de Paquete Opcional JDBC 2.0, especificamente a XA. El sewidor de contenedor EJB/aplicacion tambiin necesita ser compatible con transacciones distribuidas, en la forma de un gestor de transaccion que pueda gestionar las realizaciones de dos fases. WebLogic 6.1, que hemos estado utilizando con 10s ejemplos EJB de este libro, se adapta a las realizaciones de dos fases y ofrece sus propios controladores adaptados a XA.

Seguridad
La mayoria de las empresas tiene un requisito para proteger sus datos y procesos de accesos indebidos, tanto desde dentro como desde fuera de la empresa. La proteccidn de datos y procesos requiere 10s siguientes cuatro servicios:

Capitulo 17
O

Identificaci6n Cada usuario de un sistema seguro debe asociarse a un identificador. En 10s API de seguridad de Java, este identificador se conoce como principal. U n identificador se expresa a menudo al usuario como un "ID de usuario" durante un registro en proceso. Autentificacidn Cuando un usuario afirma que tiene una determinada identidad, debe poder presentar credenciales para demostrarlo. Frecuentemente, estas credenciales tendrin la forma de una contrasefia. Sin embargo, existen numerosas posibilidades de credenciales, como una tarjeta, un esciner de retina, una huella digital o un certificado digital almacenado en el ordenador del usuario. Todo sistema de seguro debe limitar el acceso a determinados usuarios. Cuando un usuario intenta acceder a un recurso, como una base de datos, una aplicaci6n o incluso una determinada funcion, un servicio de seguridad debe validar el derecho de ese usuario a ese recurso. El mod0 mis comun de llevar a cab0 el control de acceso es manteniendo listas de usuarios con el privilegio a acceder a recursos determinados (conocidas como listas de control de acceso).

o Control de acceso

O Confidencialidad de datos

Esto es realmente un tip0 de control de acceso pero, en la prictica, es lo suficientemente diferente como para merecer su propia categoria. La confidencialidad de datos se mantiene mediante cifrado de alg6n tipo. N o nos aporta ningun beneficio proteger nuestros datos aplicando autentificacidn cuando un usuario entra en un sistema, si otros pueden leer la contrasefia u otro tip0 de informacidn de autentificacion mientras se transmite por la red. La especificacidn EJB se centra exclusivamente en el control de acceso. La confidencialidad esti fuera de su akance, aunque un enfoque comun para una comunicaci6n segura consiste en utilizar el protocolo SSL (Secure Sockets Layer). La identification y autentificacion no forman en la actualidad parte de la especificacion EJB. De hecho, hasta hace poco, no formaban parte de ningun API Java. La seguridad en Java es algo inusual por que, a1 principio, su seguridad se concentrd en la procedencia del codigo, en lugar de en quien lo ejecutaba. Por ejemplo, cddigo que se ejecutaba desde nuestro disco duro tenia normalmente mayor acceso permitido para ejecutar diversas acciones que el cddigo procedente de la Web. Esto refleja su temprano uso que proporcionaba funcionalidad descargable dinimica en forma de applets. C o m o n o ha habido un metodo Java estindar para determinar "quien" ejecuta el codigo, 10s servidores de aplicacion debe recurrir a autentificar un usuario a traves de medios de propiedad. Por ejemplo, algunos requieren que una aplicacion cliente proporcione un parimetro de nombre de usuario y un parimetro de contrasefia en el context0 inicial JNDI, antes de buscar una interfaz inicial de un EJB. O t r o s envian al contenedor EJB la identidad provista por una implementation del protocolo SSL. Cualquier tecnica que decida utilizar el servidor de aplicaci6n es legal; este tema no se aborda en la tecnologia EJB en ninguno de sus aspectos. El API del ~ e r v i c i o de Autentificacion y Autorizaci6n de Java, Java Authenticaction and Authorization Service (JAAS) aiiade un estindar para seguridad, basado en quien ejecuta el codigo, para complementar la seguridad basada en el origen del codigo. Parte de este nuevo API proporcionar modulos de autentificacion conectables. Un cliente que utilice JAAS puede ser configurado para utilizar diferentes tkcnicas de registro, como un sencillo dialog0 de nombre de usuario/contrasefia o un lector de tarjeta inteligente conectado a1 puerto ESB de un ordenador; un servidor que utilice JAAS puede ser configurado para autentificar la identidad y credenciales del usuario (autentificacionLoginContext, en terminologia JAAS) utilizando diferentes servicios de seguridad de extremo. Puede utilizarse cualquier tecnica de seguridad posible, siempre que exista un modulo conectable. Es posible que muchos servidores de aplicacion y clientes de aplicacion normalicen este API en el futuro.

Servicios de contenedor EJB


La autentificaci6n para una deterrninada identidad puede ser provista por un servidor Netware, una base de datos Oracle, LDAP, Windows N T , un servidor Unix o un sencillo archivo XML especifico de servidor de aplicaci6n. Todo lo que se requiere es que el servidor de aplicaci6n del vendedor se ajuste al rnitodo por el que optarnos. Una vez que el servidor de la aplicaci6n valida las credenciales del usuario frente a su identidad justificada, asociari la identidad a un rol16gico que define el desarrollador o irnplernentador de la aplicaci6n EJB. Esta asociaci6n de una identidad real de seguridad del usuario con u n rol16gico de seguridad es la clave para comprender la seguridad EJB. Podernos desarrollar nuestra aplicaci6n EJB sin considerar 10s sisternas de seguridad, grupos, identidades o credenciales en uso de nuestra ernpresa. Cuando deterrninarnos 10s requisitos de seguridad de nuestra aplicacion, estarnos trabajando en un rnundo ideal y podernos especificar requisitos de seguridad a un nivel abstracto. Sin embargo, cuando la aplicacidn es verdaderarnente irnplernentada en un contenedor, 10s requisitos de seguridad abstracta deben ser entonces asociados a identidades del rnundo real de rnanera especifica a nuestro servidor de aplicaci6n e irnplernentaci6n de seguridad. Una aplicaci6n que utilice EJB puede especificar, de un rnodo estindar, portitil y abstracto, quiin esti autorizado a acceder a rnitodos de ernpresa. El contenedor EJB es responsable de las siguientes acciones:
0

Exarninar la identidad del que invoca un rnitodo de ernpresa de un rol a1 que ha sido otorgado el derecho a invocar este rnitodo de empresa

0 Exarninar la inforrnaci6n de irnlernentacion del EJB para cornprobar si la identidad es un rniernbro

Generar una excepci6n java.rrni.RemoteException si el acceso es ilegal (u otra excepcibn rnis especifica tal y corno se define en JAAS, por ejernplo, L o g i n E x c e p t i o n ) Poner la informaci6n de identidad y de rol a disposici6n del EJB para cornprobaciones de seguridad exhaustivas Registrar opcionalrnente cualquier acceso ilegal

Especificar 10s requisitos de seguridad


S61o hay dos tipos de inforrnaci6n que necesita definir el desarrollador EJB para especificar 10s requisitos de seguridad para su aplicaci6n: roles de seguridad y permisos de metodo.

Roles de seguridad
U n rol de seguridad es el rnecanisrno por el que las identidades llarnantes son asociadas a tipos abstractos, 16gicos que pueden ser utilizados en cualquier entorno de seguridad. La especificaci6n define un rol de seguridad corno una "agrupaci6n sernintica de perrnisos que un determinado tip0 de usuarios de la aplicaci6n debe tener para utilizar la aplicaci6n de forrna efectiva". En otras palabras, tipos sirnilares de actividades (corno abrir una cuenta, cerrar una cuenta y aurnentar el saldo de una cuenta) pueden ser agrupadas bajo un unico nornbre, corno "Gestor de cuentas". El servidor de la aplicaci6n proporcionari herrarnientas de irnplernentaci6n que asocian estos roles abstractos a usuarios o grupos de usuarios que existen realrnente en el entorno de seguridad de la empresa. Por ejemplo, el rol de a c c o u n t - m a n a g e r podria asociarse a todo aquel que sea rniernbro del grupo de s e p r i d a d N T "Bank Manager". En este ejernplo, siernpre que un grupo "Bank Manager"

Capitulo 1 7
invoca un metodo de empresa EJB, tendri todos 10s permisos disponibles para el rol de
account-manager.

Los roles de seguridad especificos de EJB estin definidos en el descriptor de implementacibn. Cada elemento XML destinado a definir un rol de seguridad puede tener dos elementos secundarios. El primero, el nombre del rol, es obligatorio, mientras que el segundo, la descripcibn del rol, es opcional. Sin embargo, debido que seri necesario, durante el periodo de implementacibn, asociar este rol a grupos o elementos individuales de la implementacion de seguridad del entorno de periodo de ejecucion, es bastante recomendable que proporcionemos una description. Por ejemplo, estos son algunos roles que podrian ser definidos en una aplicacion bancaria:
<security-role> <descriptinn> T h i s r n l e i n c l u d e s e v e r y b a n k e m p l o y e e who i s a l l o w e d t o a c c e s s t h e b a r ~ k i r ~a qp p l i c a t i ( 2 n . An e m p l o y e e i n t h i s r o l e may make d e p n s i t s and w i t h d r a w a l s on b e h a l f o f a t h i r d ~ a r t y . T h e y may a l s o make r e a d - o n l y i r ~ q u i r i e s f o r any information i n t h e account. </description> <role-name>teller~/rLo1e-r~ame> </security-role> (security-role> <description> T h i s r o l e i s a l l o w e d t o open and c l o s e a c c o u n t s , a d i n c r e a s e a r ~a c c o u r i t s o v e r d r a f t a l l o w a n c e . '/description> <role-name>account manager</role-name> </security-role> <security-role, <description> A u s e r i n t t ~ i sr o l e is allowed t o c l o s e e x i s t i n g accounts, withdraw and d e p o s i t money, a n d make i n q u i r i e s a b o u t t h e i r owrl a c c o u r l t o n l y . </description> <role-name\customer</roleer~ame> </security-role> < s e c u r - it y - r o l e \ <description> To p r o t e c t t h e i n t e g r i t y o f t h e d a t a , a u s e r i n t h i s r o l e is allowed read-only access t o accounts only. </description> <rale-name>executive</roleer~ame> '/security-role>

Recuerde que estos roles no tienen necesariamente equivalentes exactos en el entorno de seguridad de la empresa. Cuando se despliega la aplicacion, deben realizarse algunas asociaciones entre identidad de seguridad existentes (usuarios o grupos en la mayor parte de 10s planes de seguridad) y estos roles de seguridad EJB. Esto se lleva a cab0 de manera especifica a1 servidor de la aplicaci6n e independientemente del desarrollo de la aplicacion EJB. El desarrollador de la aplicaci6n solo necesita definir 10s roles exactos requeridos para asegurar la 16gica de empresa de un mod0 consistente y apropiado. Existe una relacion varios-a varios entre 10s roles especificos de EJB que aparecen definidos en el descriptor de implementacibn y 10s roles que existen en el sistema de seguridad del entorno. Por ejemplo, podria haber tres grupos y otros dos elementos individuales que necesitan ser asociados a1 rol "ejecutivo" definido en el ejemplo anterior: "Bank Manager", "Vice President", "Assistant VP", "John Q. Smith" y "Catherine Heigl".

Servicios de contenedor U B
Permisos de metodo
U n permiso de metodo es la asignacion a un rol de seguridad particular del derecho de invocar un metodo de ernpresa. Una vez que el rol de seguridad ha sido definido, las actividades que estin perrnitidas para ese rol deben tarnbien ser definidas. Considere nuestro ejernplo a c c o u n t - m a n a g e r . Este rol pretende representar el perrniso para realizar actividades corno abrir y cerrar una cuenta. Pero las actividades "abrir una cuenta" y "cerrar una cuenta" necesitan ser asociadas a rnetodos especificos de ernpresa, corno o p e n A c c o u n t ( ) o c l o s e A c c o u n t ( ) . Esta asociaci6n se realiza utilizando entradas, conocidas corno perrnisos de metodo, en el descriptor de irnplernentaci6n. Existe una relaci6n rnuchos-con-rnuchos entre roles y perrnisos de metodo de ernpresa. U n hnico rol puede tener perrniso para utilizar rnuchos rnetodos y rnuchos roles pueden acceder a un Gnico rnktodo. La asociacidn entre roles y rnetodos de ernpresa en el descriptor de despliegue se efectha utilizando elernentos X M L < m e t h o d - p e r m i s s i o n > . Cada elernento<me t h o d - p e r m i s s i o n > tiene una o rnis referencias de rol de seguridad, y una o rnis referencias de rnetodos de ernpresa EJB. Adicionalrnente, un elernento <method-permission>puedei n c l u i r u n e ~ e r n e n t o < d e s c r i pi to n > optional. El siguiente diagrarna representa una posible asociacion de roles de seguridad a rnetodos de ernpresa. Estos roles y rnetodos serin irnplernentados (junto con otros rnis adelante):

r Ret~rar fondos

LCancelar cuenta

Las referencias a rnetodos de ernpresa son especificados por seguridad utilizando la rnisrna sintaxis utilizada para transacciones (vease la secci6n en este capitdo sobre transacciones). Podernos especificar que 10s roles de un perrniso de metodo concreto se aplican a todos 10s rnetodos de un EJB, s d o 10s rnetodos con un nornbre deterrninado o 10s rnetodos con un nornbre deterrninado y una lista de parirnetros. ~ s t es e un ejernplo de algunos perrnisos de rnetodo de que podrian estar definidos en nuestro ejernplo del banco. Observe que s61o referenciarnos 10s roles 16gicos que hernos creado en este misrno descriptor de irnplernentaci6n, en lugar de las entidades reales de la implernentaci6n de un sisterna real de seguridad:

La combinaci6n de roles y permisos de mCtodo establece el sistema bisico de seguridad para una aplicaci6n que depende de tecnologia EJB. Este sistema puede asociarse a una combinaci6n arbitraria de usuarios del mundo real, grupos y tecnicas de autentificacibn sin alterar la aplicaci6n en absoluto. El contenedor EJB en prictica las reglas de acceso de metodo declaradas en el descriptor de implementaci6n sin mis intervenci6n por parte del programador de 16gica de empresa.

Control programado de acceso


En algunas situaciones, las politicas de s e p r i d a d de la aplicaci6n n o pueden expresarse utilizando permisos en el descriptor de implementaci6n. En ocasiones, la ejecuci6n de una operacidn depende de 10s datos que estin siendo manipulados y no de la operaci6n ejecutada. Por ejemplo, un gestor de cuentas puede estar autorizado para cerrar la cuenta de un particular pero no cualquier corporacion o entidad gubernamental. O t r o caso podria ser una gestor de divisi6n que puede solicitar matera prima para su propia divisi6n pero n o para cualquier otra. La realidad es que una gran empresa con importantes requisitos operativos de 16gica de empresa necesitari probablemente este tip0 de control de acceso controlado por datos. En otras situaciones, la ldgica de empresa puede necesitar conocer la verdadera identidad del llamante de un metodo, en lugar que simplemente el rol que desempeiia el llamante en la empresa. Esto podria ser necesario para auditar transacciones financieras o para limitar el acceso de bases de datos a s610 aquellos registros asociados a1 invocador. Para estos casos, existe un sencillo API que permite a1 programador de 16gica de empresa proporcionar control de seguridad exhaustivo por debajo del nivel de metodo de empresa. La interfaz j avax . e j b .E J B C o n t e x t , disponible como el contexto de entidad o como el contexto de sesi6n, tiene 10s dos siguientes metodos:
java.security.Principa1 getCallerPrincipal0; boolean isCallerInRole (String roleName) ;

Servicios de contenedor EIB


El metodo g e t c a l l e r p r i n c i p a l ( ) se utilizapara determinar laverdadera identidad del invocador. La interfaz P r i n c i p a l , que representa la identidad subyacente de ese Ilamante, es relativamente opaca. Ademis d e a n u l a r e q u a l s 0 , t o s t r i n g ( ) y h a s h c o d e 0 , su hnicom6todo es g e t ~ a m e 0 . Es importante comprender que el valor exacto de la principal depende del entorno operativo. Si el mecanismo subyacente de seguridad fuera modificado, el nombre devuelto de g e tName ( ) en el principal tambien podria cambiar. En otras palabras, especificar un principal determinado convertiri a nuestra aplicacion en no-portitil (no sin una cierta conversion). Ademis, el contenedor EJB podria necesitar traducir desde una principal a otra antes de invocar un metodo de empresa. Aunque n o existe un API para que un programador de 16gica de empresa controle el valor de una principal, es posible que un contenedor que se ajuste a EJB 1.1 proporcione herramientas de propiedad para configurar estas traducciones en el period0 de ejecuci6n. U n contenedor que se ajuste a EJB 2.0 proporciona un elemento descriptor deimplementacion ( < r u n - a s - e s p e c i f i e d - i d e n t i t y > ) que puede ser tambien utilizado en casos sencillos. Esto podria ser necesario en un entorno de empresa diverso como multiples sistemas de autentificaci6n. Por ejemplo, un teletrabajador puede ser identificado por un nombre de usuario y una contraseha en el sitio Web de la compafiia y seria entonces asociado a una identidad en una base de datos Oracle o un dominio NT, antes de que se pudiera acceder a1 servidor de la aplicacibn. Es posible utilizar la principal devuelta de g e t c a l l e r p r i n c i p a l ( ) para proporcionar acceso adicional a 16gica de empresa. Como regla, esto n o es una buena idea. Examinando directamente la principal en nuestro codigo, podriamos crear una dependencia en una implernentacion de seguridad particular. Probablemente la versi6n mis justificable de esto es asegurarse de que un usuario concreto solo altera su propia informaci6n. Si cambiara el sistema subyacente de seguridad, solo seria necesario cambiar las claves de registros de particulares. La peor situaci6n posible seria de c6digos refundidos en la 16gica de empresa, como 6stos:
if

(principal.getName ( // ...

==

"SMITH 076") {

El metodo i s C a l l e r I n R o l e ( ) es el mejor mod0 para determinar si el llamante de un determinado metodo tiene acceso a funcionalidad basada en 10s datos que esti intentando leer o modificar. podemos utilizar este metodo sin introducir ninguna dependencia en absoluto en la implementaci6n de seguridad subyacente. Funciona aplicando programiticamente criterios adicionales de anilisis despu6s de que el contenedor haya permitido la invocaci6n de la funci6n. Considere el caso en el que un gestor de cuentas o un ejecutivo puede cerrar la cuenta de un particular, per0 s61o un ejecutivo puede cerrar la cuenta de una corporaci6n. En el descriptor de implementaci6n, independientemente er, ambos tendrian acceso al m e t o d o c l o s e A c c o u n t ( ) del b e a n ~ c c o u n t ~ a n a ~ del tipo de cuenta. N o existe mod0 de indicar a1 contenedor EJB que el metodo c l o s e A c c o u n t ( ) debe estar disponible a ambos roles para un particular, per0 s61o uno de esos roles para una corporaci6n. Sin embargo, en la 16gica de empresa del EJB, el programador puede escribir codigo que comprobari el tip0 de cuenta y garantizar que quien intente cerrar una cuenta de una corporaci6n esti autorizado para hacerlo. Esto n o es complicado. El c6digo seria probablemente asi:
public class AccountManager implements SessionBean { private static final St ring CORPORATE ACCOUNT MANAGER = "corporate account manager"; public void closeAccount(int customerNumber, int accountNumber)
{

Customer customer = getCustomer(custamerNumber); if (customer.getType( ) == CustomerTypes.CORPORATE) I if (!lsCallerIr~Role(CORPORATE ACCOUNT MANAGER)) { throw new j ava. lang. SecurityException (

Capitulo 17
"Not authorized t o close t h i s account" ) ;

I
CustomerAccount account account. close ( ) ;
=

getSustnmerAccour~t (accountNumber);

El programador de la aplicaci6n puede diseriar una aplicaci6n para generar cualquier excepci6n en caso de un acceso ilegal. Unaposibilidad es generar j a v a . l a n g . S e c u r i t y E x c e p t i o n , derivada de R u n t i m e E x c e p t i o n . Podriamos tambien generar excepciones JAAS del tipo j a v a x . s e c u r i t y . a u t h . l o g i n . LoginExceptionoFailedLoginException.Esosignificaque cualquier transacci6n en ejecucion seri anulada, la instancia seri rechazada (probablemente destruida en este caso), la excepci6n seri registrada por el contenedor. Algunos contenedores EJB pueden ser configurados para notificar a1 sistema administrador cuando se lanzan ciertas excepciones de sistema, como S e c u r i t y E x c e p t i o n . Si alguien intenta acceder al sistema de forma inapropiada, tiene sentido que el administrador del sistema sea notificado inmediatamente. Del mismo mod0 que debemos declarar 10s recursos (corno conexiones a bases de datos) y otros EJB que referenciamos en nuestro codigo, tambiin debemos declarar 10s roles que referenciamos en nuestro c6digo. La declaracion de un rol utilizado en c6digo se realiza en la informacih del descriptor de implementaci6n relevante para ese EJB. Ese rol se vincula entonces a un rol definido como elemento c s e c u r i t y - r o l e > en el descriptor. Este nivel extra de indirecci6n permite al sistema de seguridad declarativa cambiar, sin cambiar el c6digo. Observe que en la muestra de c6digo anterior, hemos comprobado si el llamante estaba en el rol de c o r p o r a t e - a c c o u n t - m a n a g e r , per0 iste no es uno de 10s roles que habiamos estadoutilizando ( t e l l e r , a c c o u n t - m a n a g e r , c u s t o m e r o e x e c u t i v e ) . Nuestra politica actual consiste en que s d o un ejecutivo puede cerrar la cuenta de una corporaci6n, por ello utilizariamos el nivel de indirecci6n de la declaraci6n de referencia de seguridad para vincular corporate~account~manage al rrol d e e x e c u t i v e . Lainformacibn del descriptor de implementaci6n seria probablemente asi:
(security-role-ref> < d e s c r i p ticn> The c o r p o r a t e a c c a u r i t marlager r o l e i s a u t h o r i z e d t o o p e n , c l o s e , and c h a n g e t h e t e r m s an<d c o n d i t i o n s o f a c o r p o r a t e account. </description> <role-name>corporate account manaqer</role-name>

<role-link>executive</role-link>
</security-role-ref>

Observe que el elemento < r o l e - l i n k > debe ser utilizado si el r o l e - n a m e es el mismo que el elemento s e c u r i t y - r o l e que ha sido declarado como parte del sistema de seguridad de la aplicaci6n.

Seguridad y diseno de aplicacion


Por regla general, es una mala aplicacibn de disefio capacitar el acceso de la interfaz de usuario a la funcionalidad que sera rechazada por la Iogica de empresa. Si el gestor de cuentas entra en nuestro sistema y abre un registro de un cliente corporativo, 10s elementos del menG Abrir cuenta, Cerrar cuenta y Cambiar terminos deben resultar inaccesibles o ser anulados. Por otro lado, si un ejecutivo entra en nuestro sistema y abre ese mismo registro, 10s elementos del men6 deben estar accesibles y activados.

Servicios de contenedor EIB


Puesto que tste es un libro sobre prograrnacion Java de lado servidor, quizis se pregunte por q u t rnencionarnos este tema de disefio de lado cliente. En realidad, este terna de interfaz de usuario e5 tarnbien un terna de prograrnaci6n Java de lado servidor y no so10 lo es si la interfaz de usuario es una aplicacion navegador que utiliza JSP. El problerna esti en que decidir cuindo activar y desactivar el acceso de la interfaz de usuario a una funci6n particular requiere 16gica de ernpresa. Por ejernplo, puede que decidarnos que un gestor puede cerrar una cuenta de corporacion si la corporaci6n ingresa rnenos de 274.000/afio en nuestro banco; de lo contrario, solo un ejecutivo puede cerrar la cuenta. Esta es una regla de ernpresa y la logica de ernpresa es precisarnente la especialidad del servidor. Considere el problema si hernos distribuido un G U I Swing Java a nuestras 5000 sucursales bancarias y hernos refundido 10s elernentos del rnenh para que se active o desactiven basindose en la anterior regla de ernpresa. i Q u t ocurre ahora si nuestra politica cambia y una cuenta corporativa so10 puede ser cerrada por un gestor si la corporacion ingresa rnenos de 225.000/afio en nuestro banco? Necesitarnos volver a instalar todas nuestras aplicaciones cliente, quizis con un mayor gasto y esfuerzo. Si la 16gica de ernpresa de la aplicacion se lirnita a las capas de servidor, puede carnbiarse ripida y ficilrnente. Una posible solucion consiste en que el c6digo de interfaz de usuario consulte a1 servidor sobre las acciones apropiadas. El bean de sesi6n que irnplernenta el objeto interfaz del modelo de anilisis para la aplicacion podria tener rnetodos corno 10s siguientes:
public public public boolearl boolearl boolean car~lOperiAzzuurit l i n t ciustornerNurnber) c a r ~ i C l o s e A c c ~ i ? u(nit n t i ' l u s t o r n e r N u r n b e r ) ~canChar~geTerrn (s i n t custornerNurr12jerl

Sin embargo, todas estas llarnadas de rnktodos rernotos tienen corno resultado rnucho trifico de red y un rendirniento lento. Probablernente sea rnejor tener un metodo que obtenga enseguida toda la inforrnacion, siernpre que sea aceptable cierta dernora en la interfaz de usuario:
HashMap g e t c a p a b i l i t i e s I irlt ~:ustornerNurnber, List whichActivities)

La 16gica de ernpresa para el mttodo g e t c a p a b i l i t i e s ( ) podria cornbinar el rnttodo i s c a l l e r 1nRo1e ( ) con 10s datos de cornprador para deterrninar un valor booleano para cada operaci6n afiadida a la lista de consulta de actividades.

Excepciones
Aunque disefiar una estrategia de rnanejo de errores de una apkaci6n es responsabilidad del prograrnador de bgica de ernpresa, el contenedor EJB proporciona una cierta cornpatibilidad con la tarea. Concretarnente, hay dos objetivos prirnarios de la especificaci6n EJB en lo que se refiere a1 rnenos de excepciones:
0

Una excepci6n de aplicaci6n generada por el EJB o codigo relacionado deberia ser rnanejado por la logica de ernpresa Una excepci6n n o esperada o una excepci6n de sistema generada por el EJB o c6digo relacionado deberia ser rnanejada por el contenedor EJB
()

El rnanejo habitual de una excepci6n es una llarnada para realizar(comrnit ( ) ) o deshacer ( r o l l b a c k la transaction relevante. Adernis, 10s recursos especificos a la instancia de bean necesitan rnantenerse consistentes. La 16gica de ernpresa es responsable de la consistencia de recursos con excepciones de aplicaci6n y el contenedor es responsable de las excepciones no esperadas.

Capitulo 17

Excepciones de aplicacion
Una excepci6n de aplicaci6n es cualquier excepci6n que se declare en la cliusula throws de un metodo en la interfaz inicial o remota de un EJB; except0 j ava .rmi .RemoteException. una excepci6n de aplicaci6nnodebederivardej ava. 1ang.RuntimeExceptiono java. rmi. RemoteException porque kstas se definen como excepciones de sistema y serin tratadas de forma diferente por el contenedor EJB. Ademis, puesto que estas excepciones son definidas y generadas por la aplicaci6n, deben ser enviadas de vuelta a1 cliente, a1 contrario que EJBExceptions, que tienen un mayor impact0 en el nivel del contenedor (rechazando instancias de beans, etc.). Una excepci6n de aplicaci6n puede derivar de j ava . lang .Except ion o d e otras clases de excepci6n de una jerarquia de manejo de excepciones. Sin embargo, hay diversas excepciones de aplicaci6n predefinidas en la especificaci6n EJB relacionadas con DuplicateKeyException, n, diversas retrollamadas de c o n t e n e d o r : ~ r e a t e ~ x c e p t i o FinderException,ObjectNotFoundExceptionyRemoveException. Para garantizar que una excepci6n de aplicacibn puede ser manejada por un EJB o por c6digo cliente, la especificaci6n requiere que una excepcion de aplicaci6n lanzada por una instancia EJB debe ser comunicada a1 cliente con precision. En otras palabras, el cliente obtiene exactamente la misma excepci6n que ha lanzado el EJB. Esto puede parecer obvio: {que otra excepcion podria obtener? Sin embargo, veremos que esta regla no alberga excepciones (no-aplicacion) no esperadas. Recuerde que existe una capa de interposicion entre el cliente y el EJB, y el que el c6digo de EJB nunca es invocado directamente. Por ello es posible que el contenedor EJB transforme arbitrariamente excepciones de un tip0 en otro. La especificacion convierte esta opci6n en ilegal.

Observe que esto signifi:ca que cualquier excepcidn de aplicacio'n declarada en la clase de implementacio'n EJB debe ser tambiin declarada en la interfaz remota del bean. Lo contrario, sin embargo, no es cierto. S61o porque la interfaz remota del bean declara que lanza una excepcio'n, no signifi:ca que la clase de implementacidn deba hacer lo mismo.
Una excepci6n de aplicaci6n lanzada desde un metodo que participa en una transacci6n no necesariamente deshacer esa transaction. De nuevo, esto es asi para dar a la 16gica de empresa del llamante una oportunidad de emprender acciones para recuperarse. Si el desarrollador del codigo que lanza esa recuperacion sabe que la recuperaci6n es imposible, pude marcar la transaccibn para que sea anulada. Consideremos un ejemplo completo. Tomemos el caso de un bean de sesi6n de comprador que invoca el metodo debitAccount ( ) de otro bean de sesi6n en una transacci6n. Suponga que el metodo de retirar dinero genera una excepcih de aplicaci6n llamada Insufficient FundsException si la cuenta no tiene suficiente dinero para cubrir el cargo. Debido a las reglas del lenguaje de programacion Java, el metodo debe capturar la excepci6n o declarar que la genera. Podria resultar apropiado, dependiendo de 10s requisitos de la aplicaci6n. Consideremos primero el caso en el que la aplicaci6n podria querer recuperarse de la exception, intentando cargar una cantidad menor:
p r i v a t e d o u b l e atternptDebit(doub1e amount, S t r i n g customer) AccountManager accour~tManager = getAccourttMar~agerBea( r~ ) ; try i accountManager .debitFur~ds ( arndunt, c u s t o m e r ) ; 1 c a t c h ( I n s u f f i c i e n t F u n d s E . u c e ~ t i o r i~n s u f f i c i e r ~ )t { try { a m o u r ~ t / = 2; account-Manager. d e b i t Funds (amount, c u s t o m e r ) ; } catch (Exception e ) [ t h r o w new E J B E x c e p t i o n ( e );
)
} {

catch

(RemoteException r e )

Servicios de contenedor U B
throw
1

new

E J B E x c e p t i o n ire);

return

amount;

Si el m i t o d o d e b i t Funds ( ) de empresa d e ~ c c o u n t ~ a n a g e generaunaexcepcion r Insufficient FundsException,intentamos un segundo cargo con la mitad del dinero original. Este nuevo intento puede tener ixito, si hay suficientes fondos en la cuenta para cubrir la nueva solicitud. La 16gica de empresa de este mitodo no es realista, per0 es ficil de extrapolar a una situacion real. Observe 10s resultados; se lanza una excepcidn pero la 16gica de empresa maneja la recuperation. Asumiendo que habia fondos suficientes para cubrir la nueva cantidad de cargo, la transaccidn puede realizarse con ixito a1 final del procesamiento. Sin embargo, si ha7 suficientes fondos para cubrir la nueva cantidad de cargo, se lanza una excepci6n E JBExcept ion. Esta es una excepci6n de sistema, explicada en la siguiente secci6n. Este ejemplo e s t i estructurado para mostrar el amplio espectro de opciones de manejo de excepciones. En la prictica, un mitodo de empresa debe normalmente volver a lanzar una excepci6n de aplicacidn si no puede recuperase, para dar a la funcion de llamada la oportunidad de recuperarse, como se demuestra a continuacih. Nuestros mitodos de empresa no tienen que capturar excepciones si no estin seguros de como manejarlas. Podemos simplemente declarar esta excepci6n en nuestra firma y dejar a1 llamante que se encargue de ella. Por ejemplo, en el siguiente codigo, el mitodo at temptDebit ( ) realiza una operaci6n que podria provocar una excepcion Insuf f icient FundsException. Puesto que no hemos especificado exactamente q u i debe hacer el mitodo attemptDebit ( ) en este caso (volver a intentarlo, notificar a1 usuario, etc.), no hari nada. La excepcion se pasari a1 Ilamante, que tomari las medidas apropiadas (o posiblemente pasari la excepci6n a su Ilamante). El c6digo sera ask
private atternptDebit ( d o u b l e amount, Strirlq c u s t o m e r ) throws Insuf f icientFur~dsExceptiorl I A c c c ~ u r ~ t M a n a g ea r c c o u n t M a n a g e r = q e t A c c ~ ~ u r ~ t M a r ~ a g e r iB) ?;a r ~ double

try
}

i
accountMar~ager.debitFunds( a m ~ u r ~ tc, u s t o m e r ) ;
(Reni,:t?Exceptiori r e ) { new E J B E x ~ e p t i u n ( r e 1 ;

catch throw

returrl

amount;

Si el parimetro amount es superior a 10s fondos disponibles, el bean AccountManager lanzari InsufficientFundsException.En~ugardecapturar~a,e~mitodoattempt~ebit ( ) declaraensu firma que lanza esa excepcion. Si este mitodo attemptDebit ( ) fuera invocado en el context0 de una transacci6n existente, es responsabilidad del llamante recuperarse de la excepcidn o volver a generarla. Esta es la misma situaci6n que hemos visto con debit Funds ( ) en la version anterior de att emptDebi t ( ) . Podriamos elegir la recuperacih de la e x c e p c i h o pasarla en la cadena de llamada. Si el contenedor empezara directamente una nueva transacci6n antes de invocar attemptDebit ( ) , esa transaccih debe completarse cuando vuelva attemptDebit ( ) . En este punto, cualquier mitodo e j bstore ( ) necesario seria invocado y se realizarian 10s cambios en el almacin persistente. { Q u i sucede en este caso, cuando el mitodo de empresa para el que se inici6 la transacci6n genera una excepcibn? El contenedor EJB intentaria realizar todos 10s cambios en la base de datos y, por supuesto, el cliente obtendria la excepci6n generada. Esto quizis sea poco intuitivo pero es un punto importante de comprender. Incluso si generamos una excepci6n de aplicacion que no es capturada antes de ser lanzada el cliente, el contenedor EJB todavia intentari realizar nuestra transaccion.

Capitulo 17

Generar una excepci6n no es equivalente a deshacer todos 10s cambios.

Puede suceder que, en ciertas circunstancias, el metodo debit Funds ( ) haya realizado cambios en la base de datos que hacian obligatoria la anulaci6n de la transaccidn. En otras palabras, n o quiere que el mttodo de ernpresa attemptDebit ( ) ni ningun otro mttodo sea completado con txito. Utilizando la interfaz inte on text ( ) (a traves de la sub-interfaz sessioncontext o Ent it ycontext ( ) ), el bean que lanza la excepci6n de aplicaci6n puede marcar la transaccion para ser anulada, a travCs del metodo setRollbackOnly ( ) . El c6digo cliente que captura la excepci6n puede deterrninar si la transacci6n ha sido marcada para ser anulada invocando el mttodo getRol lbackOnl y ( ) de EJBContext. Existen metodos equivalentes en la interfaz UserTransact ion para beans con transacciones gestionadas por beans: getstatus ( ) y setRollbackOnly ( ) . Imaginemos que, antes de intentar retirar 10s fondos, imponemos una tasa a1 comprador para uso de la cuenta. Primero necesitamos realizar esta operacidn porque, si vamos a imponer la tasa, es necesario que haya suficiente dinero la cuenta para el cargo y para la tasa. Sin ernbargo, si falla el cargo, necesitarnos asegurarnos de que la transacci6n hasta ese punto n o se ha realizado o, de n o ser asi, estaremos cargando la tasa por una actividad que nunca ha tenido lugar. La logica de ernpresa para el metodo debit Funds ( ) puede ser asi:
p u b l i c c l a s s Aic~>~intMar~agel-E im JB plements public SessionCvntext c t ~ ; public try SessionBean
{

viiid d e h i t f ~ l r l d . c ( d o u b l e amount, S t r i r ~ gc u s t o m e r ) t h r o w s In.cufficientFur~dsException {

Bar,Prlustorner b a r , l : C ~ ~ s t o m e r = getBankCustomer ( c u s t ~ 9 r n e; ~-) bar~kCustorner. impnseFeeForActivity ( ) ; bar~kCustornerw . ithdrawFur1ds ( ) ; c a t c h [ I r l s u f f i s i e r ~ t F u r ~ d s E x c e p t i o r ii f e ) { ctx. setRollbackOr~ly ( ) ; throw i f e ; c a t c h ( R e m o t e E x c e p t i o r ~e ) { t h r o w new E J B E x c e p t i o n ( e ) ;

1
I
p l ~ b l i cvoid setSessiorlContezt (SessiorlCorite~tc t x ) this.ctx = ctx;
{

I n c h s o si un metodo de ernpresa captura la excepci6n InsufficientFundsException mas adelante en la cadena de la llarnada y hay un intento de recuperacion, la transacci6n nunca se realizara una vez se haya invocado setRol lbackOnl y ( ) . C o m o resultado, la tasa por actividad de este ejemplo nunca se aplicari, incluso si ya hemos invocado el metodo i m p o s e F e e F o r A c t i v i t y ( ) . P o r supuesto, esto hace que cualquier procesamiento posterior resulte inutil. Si es posible que un mCtodo de empresa que genera una excepci6n de aplicaci6n haya marcado una transaccion para ser anulada, 10s clientes de ese mktodo (por ejemplo, otros EJB) de la misma transaccion deben comprobar a traves de g e t R o l l b a c k O n l y ( ) si esto es cierto, antes de continuar con el procesamiento. Observe que 10s mCtodos getRollbackOn1 y ( ) y setRollbackOnly ( ) s61o deben utilizarse con beans CMP. Los beans BMP manejan las transacciones ellos rnisrnos, por lo que pueden deshacer sus transacciones directamente.

Servicios de contenedor U B
Excepciones de aplicacion predefinidas
Existen cinco excepciones de aplicaci6n predefinidas utilizadas en la tecnologia Enterprise JavaBeans: Una excepcion c r e a t e E x c e p t i o n o cualquier subclase indica que ha tenido lugar una excepci6n de nivel de aplicaci6n durante una operaci6n c r e a t e ( ) en una interfaz inicial. Esta puede ser generada por el desarrollador EJB desde e j b c r e a t e ( ) o (para beans de entidad) desde e j b p o s t c r e a t e ( ) . En persistencia gestionada por bean y persistencia gestionada por contenedor, el EJB puede generar C r e a t e E x c e p t i o n para beans. Para un bean de entidad con persistencia gestionada por contenedor o para un bean de sesion, tambikn podria ser generada por el contenedor. U n uso habitual de C r e a t e E x c e p t i o n podria sere1 caso en el que el mktodo c r e a t e ( ) proporcionara parimetros no d i d o s . Las reglas habituales para excepciones de aplicacidn se aplican a C r e a t e E x c e p t i o n : la transacci6n debe marcarse para ser anulada si esti amenazada la integridad de 10s datos; si no es asi, debe darse a1 c6digo cliente una oportunidad de recuperacion. n. se Laexcepcion D u p l i c a t e K e y E x c e p t i o n e s unasubclase d e c r e a t e ~ x c e ~ t i oIndicaque ha violado una restriccion de datos como una clave primaria o una clave externa. Como la base de datos subyacente esti normalmente protegida frente a actualizaciones que violan una restricci6n de clave, habitualmente no hay ninguna raz6n para marcar la transacci6n para ser anulada. Una excepcion F i n d e r E x c e p t i o n o cualquier subclase indica que ha tenido lugar una excepci6n de nivel de aplicacion durante una operaci6n f indXXX ( ) en una interfaz inicial. En el caso de la persistencia gestionada por bean, esta excepcion se genera desde 10s mktodos e j bFindXXX ( ) de la clase de implementacibn. En el caso de la persistencia gestionada por contenedor, la excepci6n seri ejecutada por el contenedor EJB si es necesario. Puesto que 10s mktodos buscadores no cambian n i n g h dato, no existe en realidad ningun motivo para marcar la transaction para ser anulada. n. que laentidad La excepci6n o b j e c t N o t F o u n d es una subclase d e ~ i n d e r ~ x c e p t i oIndica solicitada por el metodo no existe. Observe que 10s metodos buscadores que devuelven una C o l l e c t i o n o E n u m e r a t i o n no deben utilizar esta excepcidn pero, en su lugar, deben devolver una C o l l e c t i o n o E n u m e r a t i o n vacias. Como 10s mktodos buscadores no alteran 10s datos, no existe normalmente ninguna raz6n para marcar la transacci6n para ser anulada. La excepci6n RemoveExcePt i o n indica que una excepci6n de nivel de aplicaci6n ha tenido lugar a1 intentar eliminar el bean. Puede ser lanzada por el desarrollador EJB desde el metodo e j bRemove ( ) o por el contenedor. Las reglas habituales para excepciones de aplicaci6n se aplican a C r e a t e E x c e p t i o n : la transacci6n debe ser marcada para ser anulada si esti amenazada la integridad de 10s datos; de lo contrario, debe darse a1 c6digo cliente una oportunidad para su recuperacion.

Excepciones de sistema
Una excepci6n de sistema es una excepci6n de la que la aplicaci6n no espera recuperarse. La especificaci6n EJB enumera diversos ejemplos de citaciones en las que esto puede ocurrir:
0 0 0 0 0

Fallo a1 obtener una conexi6n a una base de datos Excepciones de API JNDI
E x c e p c i 6 n ~ u n ~ i m e ~ x c e p tno i o esperada n (comounaNullPointerException)

Error de JVM Excepci6n R e m o t e E x c e p t i o n no esperada procedente de la invocacidn de otros EJB

Capitulo 17
Aunque la 16gica de empresa tiene libertad para tener c6digo de recuperaci6n para cualquiera de estas situaciones, es bastante probable que la recuperacion no sea posible. Por ejemplo, no poder obtener una conexion a una base de datos u obtener una excepci6n del API J N D I significa con toda probabilidad que la aplicacibn ha sido configurada err6neamente en el period0 de implementaci6n. N o existe ningun modo portitil para que un EJB ajuste su despliegue en el contenedor EJB, incluso si pudiera determinarse una estrategia para un entorno concreto, que es bastante improbable, de todas formas. Escribir codigo para la recuperaci6n de una excepcion R u n T i m e E x c e p t i o n no esperada es a menudo un enfoque derrochador porque tal c6digo de recuperaci6n puede traducirse normalmente en comprobacion de condiciones previas. En lugar de generar Nu1 1P o i n t e r E x c e p t i o n , capturarla y deducir quk ha fallado, podriamos simplemente comprobar 10s parimetros con la 16gica de empresa para asegurarnos que no son nulos. Si todavia obtenemos una excepci6n no esperada, algo ha fallado con el codigo y es adecuada la recuperaci6n. Siempre que se genera una excepci6n de sistema, el contenedor EJB debe registrar la excepci6n. Esto se debe a que una excepcion de sistema a menudo indica que hay un problema que requiere la atenci6n de un administrador del sistema. Por ejemplo, el fa110 a1 obtener una conexion a la base de datos puede deberse a un error de configuraci6n con el contenedor EJB, un problema de licencia con la base de datos, un problema de autentificacidn para la conexi6n, etc. S61o si se registra el problema en a l g h registro, el administrador del sistema lo tratari de forma efectiva. Opcionalmente, un servidor de aplicaci6n puede proporcionar servicios como e-mail o notificaci6n de buscapersonas cuando tengan lugar ciertas excepciones de sistema. El contenedor EJB proporciona dos servicios de recuperacion para colaborar en que el estado de la aplicaci6n permanezca consistente frente a una excepci6n de sistema. En primer lugar, la excepci6n actual se anula. Es diferente a la excepcion de aplicacibn, donde el contenedor EJB intenta realizar la transacci6n independientemente del manejo de excepciones. Si un metodo de empresa genera una excepci6n de sistema, no se realiza ninghn cambio o actualizacidn de base de datos asociados a esa transacci61-1, independientemente de 10s intentos del cliente en la recuperaci6n. El contenedor EJB deshace la transacci6n actual cuando sucede una excepci6n de sistema de mod0 que el programador de la ldgica de empresa no necesita rodear cada metodo de empresa con c6digo de recuperaci6n de error. En el caso de una excepcion de aplicaci6n, el desarrollador de bean puede indicar si una transacci6n debe o no ser anulada configurando s e t R o l l b a c k o n l y ( ) . Para tener la misma capacidad para una excepci6n de sistema, cada metodo de empresa tendri que capturar cualquier excepcion derivada de j a v a l a n g .T h r o w a b l e y determinar en el bloque c a t c h si marcar o no la transaction para ser anulada. Para empeorar las cosas, no habria necesariamente suficiente informacidn semintica en la excepci6n para decidir si era posible o no la recuperacion por otro metodo de empresa. Esa excepci6n N u l l P o i n t e r E x c e p t i o n , <tuvolugar antes o despuks de que la base de datos fuera actualizada? N o hay mod0 posible de decirlo, sin afiadir incluso mas c6digo de manejo de excepciones.

El segundo servicio de recuperaci6n que proporciona el contenedor para asegurar que el estado de la aplicaci6n sigue siendo consistente frente a una excepci6n de sistema, consiste en rechazar la instancia EJB. En otras palabras, una vez que un bean lanza una excepci6n de sistema, no se invocari ningun otro metodo de empresa o de retrollamada en esa instancia de clase Java.

La ventaja de que el contenedor rechace la instancia es que el programador de 16gica de empresa no necesita
garantizar que el estado no transaccional de ese bean es consistente. Por ejemplo, imagine un bean de sesi6n sin estado que ha utilizado una conexi6n de socket para trabajar. En lugar de crear una nueva conexi6n para cada llamada de mitodo de empresa, podriamos crear una Gnica conexi6n de socket reutilizable en cada metodo e j b C r e a t e ( ) de la instancia de bean de sesi6n sin estado. Si nos interrumpiera una excepci6n no esperada en medio del procesamiento, ese socket podria quedar con datos no leidos de una solicitud anterior. Si reutiliziramos esta instancia para otra llamada de metodo de empresa, esa llamada de metodo de empresa podria fallar porque la conexi6n de socket estaba fuera de sincronizaci6n. Esto es s610 un ejemplo; existen muchas formas en las que el estado de un EJB puede ser alterado por una excepci6n de sistema no esperada. Puesto que la especificaci6n EJB otorga gran valor a las virtudes de fiabilidad y estabilidad, el mod0 de acci6n mis seguro (rechazar la instancia) es establece como obligatorio.

Servicios de contenedor EJB


Quizis se pregunte quk ocurre desde el punto de vista del cliente despuks de que una instancia ser rechazada. iPuede el cliente seguir utilizando su referencia remota a ese bean? Para un bean de entidad o un bean de sesi6n sin estado, la respuesta es si. Este comportamiento es establecido como obligatorio por la especificacion y todos 10s contenedores EJB adaptados lo permitirin. Esto se debe a que, para beans de entidad o beans de sesi6n sin estado, el contenedor simplemente puede delegar futuras llamadas en una instancia diferentes del EJB. Sin embargo, un bean de sesi6n cuyo mktodo de empresa genera una excepci6n de sistema dejari de existir desde el punto de vista del cliente. Cualquier invocaci6n posterior a travks de la interfaz remota puede generar j a v a .r m i .NoSuchOb j e c t E x c e p t i o n . Esto puede provocar una cantidad significativa de trabajo perdido, por lo que un programador que utilice un bean de sesi6n con estado debe tener especial cuidado con las circunstancias en las que permite que se 'genere una excepci6n de sistema. Q u i z i nos preguntemos qu6 sucede con 10s recursos del bean rechazado, puesto que el desarrollador de bean no tiene oportunidad de invocar n i n g h cddigo de limpieza despuks de generar una excepci6n de sistema. iQuk ocurre con 10s sockets abiertos, las conexiones a bases de datos, etc. despuks de haberse lanzado una excepcidn de sistema? El contenedor EJB debe re~~onsabilizarse y cerrar inmediatamente cualquier recurso que haya sido obtenido a travks de una factoria de recursos que utilice el espacio de nombre JNDI. por desgracia, el contenedor probablemente no pueda cerrar ninguno de 10s recursos que hayamos obtenido utilizando 10s API JDK, como una conexi6n TCP/IP. Estos recursos serdn cerrados eventualmente durante el proceso habitual de recolecci6n de basura. Una excepcion de sistema definida por el usuario debe derivar de j a v a .l a n g .RunTimeExcept i o n o de j a v a . r m i .R e m o t e E x c e p t i o n . adicionalmente, las excepciones derivadas de j a v a . l a n g .E r r o r son consideradas excepciones de sistema, aunque j a v a . l a n g .E r r o r no esti destinadapara el uso de programadores de aplicaci6n. Los programadores deben seguir estas tres reglas bisicas para determinar quk excepci6n de sistema lanzar:
O

Si el contenedor EJB se encuentra con una excepci6n derivada de R u n t i m e E x c e p t i o n o E r r o r , simplemente debe propagar esa excepci6n o error a1 contenedor. En otras palabras, el programador de bgica de empresa no debe preocuparse de capturar esos errores (a menos que 10s espere y tenga una estrategia de recuperaci6n). Si el EJB se encuentra con una excepci6n comprobada de la que no puede recuperarse, debe envolver la excepci6n original en la clase j a v a x .e j b .E J B E x c e p t i o n (pasando la excepci6n original como parimetro a1 constructor de la ~ ~ ~ ~ x c e ~ Puesto t i o n que ) .E J B E x c e p t i o n se deriva de R u n T i m e E x c e p t i o n , no es necesario declararla en la cliusula t h r o w s de un mktodo de empresa. Recuerde que lanzar una E J B E x c e p t i o n o cualquier otra clase derivada de R u n t i m e E x c e p t i o n , provocari que la transacci6n sea anulada y la instancia de bean sea recolectada como residuo. Si el EJB puede recuperarse marcando la transacci6n para ser anulada y lanzando una excepci6n de aplicaci6n, ksta es la estrategia preferida. Si el EJB se encuentra con cualquier otra condition de error de la que no puede recuperarse, debe simplemente lanzar una instancia de j a v a x .e j b .E J B E x c e p t i o n , que puede envolver la excepcidn original o el mensaje de error.

A diferencia de las excepciones de aplicaci6n, un cliente no recibe una excepci6n de sistema tal y como ha sido generada por el EJB; el contenedor traduce cada excepcion de sistema en una excepci6n java.rmi.RemoteExceptiono en una subclase. Esto simplifica enormemente el manejo de error para el cliente. En lugar de preocuparse sobre capturar excepciones dispersas I l l e g a l A r g u m e n t E x c e p t i o n s o I n d e x O u t O f B o u n d s E x c e p t i o n s que vuelven de una llamada a1 servidor, el cliente s61o trata una excepcidn c o m p r o b a d a : ~ e m o t e ~ x c e ipo tn . Si el EJB que genera la excepci6n esti participando en una transacci6n de cliente, notificari a ese cliente que es inlitil seguir procesando la transacci6n lanzando una subclase de j a v a . r m i .R e m o t e E x c e p t i o n llamada j a v a x . t r a n s a c t i o n . TransactionRolledbackException.Si hay uncontextode

Capitulo 17
transaccidn n o especificado o si el contenedor ha empezado la transaccidn actual justo antes de que se invocara ese metodo de empresa, el contenedor generari una sencilla R e m o t e E x c e p t i o n . Para facilitar la compatibilidad descendente con la versidn 1.0 de la especificacidn EJB, un EJB puede generar una R e m o t e E x c e p t i o n que seri tratada como una excepcidn de sistema. Esta es la Gnica excepcidn comprobada que es tratada como una excepcidn de sistema. Esta prictica no esti aprobada y no deberiamos, por lo tanto, llevarla a cabo. Como regla general, nunca debemos generar una R e m o t e E x c e p t i o n desde ningGn metodo de nuestra clase de implementacidn. Dicho esto, no existe ninguna consecuencia si lo hacemos.

La especificacidn EJB pone en prictica reglas que son diseiiadas para apoyar el acceso distribuido a componentes. La regla mis importante es que las interfaces inicial y remota son definidas como interfaces
RMI. Esto simplifica el uso de una implementacidn de RMI como protocolo de acceso remoto. Otra regla es que el parimetro de metodo y 10s tipos de retorno deben ser valores legales para RMI-IIOP, lo cual posibilita el uso de una implementacidn de RMI sobre IIOP.

RMI-IIOP fue incluido en la especificacidn EJB principalmente para proporcionar interoperatividad con sistemas C O R B A de legado. Aunque se tram de hecho de un requisito en algunos casos, esta interaccidn es habitualmente limitada ya que RMI-IIOP no apoya conceptos avanzados ofrecidos tradicionalmente en servidores de aplicaci6n, como apoyo transaccional, operacidn de agrupamiento o clustering, relevo, equilibrio de carga, etc.
Una de las caracteristicas mis interesantes de la especificacidn EJB 1.1 es que no establece en uso obligatorio de RMI o de cualquier otra interfaz o implementacidn de comunicacidn distribuida concreta. Una opcidn es utilizar la versidn "nativa" de RMI Java Remote Method Protocol (JRMP), aunque en 10s JDK hasta 1.3 (este incluido), esta opcidn impondria limitaciones en el nGmero de clientes remotos debido el mod0 de implementacidn de JRMP. Diversos vendedores de contenedores EJB han implementado su propia versidn de M I . Oros vendedores han optado por utilizar una versidn de RMI que se ejecuta sobre IIOP. La especificacion EJB 2.0 requiere que 10s vendedores proporcionen apoyo para RMI-IIOP. Esto es asi para garantizar que 10s contenedores EJB pueden interoperar en un nivel bisico; sin embargo, 10s vendedores de contenedor EJB pueden ofrece; tambien otros protocolos.

Comunicacion entre servidores heterogeneos


La comunicacidn entre sewidores de aplicacidn heterogeneos es mis dificil de conseguir de lo que podria parecer a primera vista. El problema es que existe un estado asociado a cada llamada de metodo, como el context0 de transaccidn y la identidad de seguridad del llamante. En le especificacidn Enterprise JavaBeans 2.0 o en la especificacidn de Rh4I no se define cdmo trasladar este estado desde el EJB cliente a1 EJB sewidor. Esta falta de compatibilidad de period0 de ejecucidn entre contenedores EJB se considera un punto debil de la situacidn actual.

La especificacidn EJB 2.0 si especificad RMI-IIOP como la solucidn a1 problema de interoperatividad. Sin
embargo, la especificacidn 2.0 ha convertido en opcional la interoperatividad de transacciones y ciertos aspectos de interoperatividad de seguridad. En otras palabras, la situacidn no esti todavia del todo resuelta, aunque se han realizado progresos significativos.

Servicios de contenedor EJB


Una de las ventajas del protocolo RMI-IIOP es que puede proporcionar acceso a EJB desde clientes no Java. U n ejemplo excelente del acceso a clientes no Java que puede facilitar R M I - I I O P es 10s Servicios C O M de Acceso a Cliente. C O M es u n Modelo de Objeto Componente de Microsoft y este buente bennite a 10s desarrolladores crear clientes nativos MS- Windows aue acceden a E TB directamente. Proporcionar un modelo de objeto esta'ndar que sirve como base para todo, desde servicios de blataforma Windows como arrastrar v soltar. hasta comunicaciones distribuidas. pasando por control de transacciones y equilibrio de carga. El puente proporciona u n conjunto de objetos C O M aue permite a las atdicaciones cliente de Windows establecer una conexidn con u n ' servidor de aplicacidn y encontrar o crear referencias a EJB. Las referencias a EJB son presentadas a1 cliente como objetos C O M . Esta'n surgiendo otros protocolos para capacitar la comunicacidn entre sistema heteroge'neos, como Simple Object Access Protocol ( S O A P ) o Java Connector Architecture (JCA).
A ,

Hay cuatro tipos de asbciaciones CORBA-EJB explicitas o implicitas en la especificaci6n EJB 2.0: distribuci611, nombrado, transacciones y seguridad:

O La asociaci6n de distribuci6n describe el I D L CORBA para las interfaces y clases. Esta asociaci6n es implicita desde el punto de vista del programador de la aplicaci6n cuando se utiliza un cliente Java. O La asociaci6n de nombrado establece que el sewicio CosNaming O M G sea utilizado para publicar y resolver objetos EJBHome. U n tipico cliente Java, incluido componentes Java de lado sewidor como otros EJB, sewlets y piginas JSP, todavia utilizarian las interfaces J N D I Java estindar para acceder a CosNamineSewice. El im~lementador de una a~licaci6n cliente obtendria la direcci6n del w host y el nimero de puerto del sewicio CosNaming del sewidor y el nombre CosNaming de cada el contenedor cliente consecuentemente utilizando interfaz inicial referenciada v confieuraria w herramientas especificas de sewidor de aplicaci6n. El programador de cliente y el desarrollador EJB no necesitan nada para ajustarse a la asociaci6n de nombres EJB-CORBA. O La asociaci6n de transacci6n proporciona reglas para un period0 de ejecucidn EJB que desea utilizar una implementaci6n de la versi6n 1.1 del Sewicio de Transacci6n de Objetos CORBA (OTS) para apoyo de transacciones. La propagaci6n de transacciones esti definida por completo en una especificaci6n OMG; la asociaci6n s610 especifica las reglas que permiten la propagaci6n de context0 de transacci6n para EJB, basada en OTS. La propagaci6n de transacciones entre contenedores EJB heterogkneos no se establece como obligatoria en la especificaci6n EJB 2.0. Existen reglas que deben seguir 10s vendedores de contenedores EJB si deciden no proporcionar interoperatividad de transacciones. O La ultima asociaci6n es la asociaci6n de seguridad. Las comunicaciones seguras son proporcionadas a travks de compatibilidad obligatorio con el protocolo SSL. La propagaci6n interoperable de la identidad del llamante es provista a travks de RMI-IIOP de acuerdo con el estindar CORBA de la versi6n 2 de Common Secure Interoperability (CSIv2). Sin embargo, la compatibilidad con la propagaci6n de datos de autentificacibn entre contenedores heterogkneos n o es obligatoria. En cambio, es posible configurar "relaciones de confianza" entre EJB o contenedores Web para hacer que resulte innecesaria una mayor autentificaci6n.
El punto fundamental es que CORBA todavia no proporciona interoperatividad perfecta entre diferentes sewidores de aplicaci6n basados en ORB y, por supuesto, no proporciona ninguna ayuda para la interoperatividad con un sewidor de aplicaci6n EJB 1.1 no basado en ORB. Es probable que futuras versiones de la especificaci6n intenten especificar de un modo mis completo la asociaci6n CORBA/EJB para permitir la interoperatividad completa entre todos 10s contenedores EJB. Sin embargo, en la actualidad, la interoperatividad disponible para contenedores EJB 2.0 puede ser suficiente para cubrir nuestras necesidades.

Capitulo 17

Llamadas de metodo en VM
Si una llamada de metodo de un EJB a otro tiene lugar en una Gnica miquina virtual Java, n o es necesario utilizar toda la "maquinaria" de comunicaci6n rernota, como el empaquetamiento de parimetros y estado de contexto para transporte de red. C o m o hemos explicado en el capitulo anterior, la especificacion EJB 2.0 se enfrenta a este problema introduciendo interfaces locales. Las llamadas realizadas en inicios locales u objetos EJB locales son realizadas por referencia, igual que las llamadas Java estindar. Esto tiene un efecto direct0 sobre c6mo debemos estructurar la arquitectura de nuestras aplicaciones J2EE. La especificaci6n EJB 2.0 establece que s61o 10s EJB de la misma unidad de implementaci6n (un archivo EAR) pueden buscar e invocar rnetodos en interfaces locales. Por lo tanto, debemos ubicar EJB y archivos JSP (o servlets) en el mismo archivo EAR, asegurando asi que el servidor de aplicaci6n optimizari las llamadas entre ellos.

En este capitulo, hernos examinado cuatro servicios especificos que proporcionari un contenedor EJB: 0 Compatibilidad transaccional 0 Seguridad 0 Manejo de excepciones 0 Comunicaciones Aunque el proposito de la tecnologia Enterprise JavaBeans es liberar a1 programador de 16gica de empresa de tener que desarrollar servicios de nivel de sistema, debemos comprender sin embargo c6mo funcionan estos servicios en el contexto de EJB. Los servicios importantes que hemos abarcado son: El completo aislamiento de una transacci6n serin intercambiado con frecuencia por una aumento en el rendimiento. El comportamiento de 10s mktodos de empresa en una transacci6n puede ser controlado de forma declarativa (el metodo preferido) o prograrniticamente. La seguridad es un requisito importante para la mayoria de aplicaciones de empresa y comprende identificacibn, autentificaci6n, control de acceso y confidencialidad de datos. La especificaci6n EJB se encarga ella misma del control de acceso. La seguridad es especificada declarativamente en el descriptor de irnplementaci6n, utilizando roles de seguridad y permisos de metodo. El c6digo de 16gica de empresa puede acceder a la identidad del invocador de un metodo de empresa y puede tambien determinar si participa en una determinado rol. Existen dos tipos de excepciones: excepciones de aplicaci6n y excepciones de sistema. El programador de 16gica de empresa es responsable de la recuperaci6n de excepciones de aplicaci6n. La transacci6n actual intentari realizarse a pesar de una excepci6n de aplicacibn, a menos que la transacci6n s61o este configurada para se anulada. El contenedor EJB es responsable de la recuperaci6n de excepciones de sistema. Cualquier transacci6n actual seri anulada y la instancia de bean seri rechazada.

Servicios de contenedor EJB


La especificaci6n EJB proporciona reglas que son disefiadas para facilitar la comunicaci6n remota.
O

Las reglas para la comunicaci6n entre servidores de diferentes vendedores no estin adecuadamente especificadas en esta versi6n de la especificaci6n EJB.

En el siguiente capitulo, examinaremos el proceso de desarrollo para EJB. La especificaci6n EJB 2.0 define varios roles adoptados en la producci6n y utilizaci6n de una apkaci6n basada en componentes EJB. Comprender estos roles nos ayudari a comprender las razones que estin detris de las decisiones de disefio de tecnologia EJB y nos asistirin en el desarrollo y uso de nuestra aplicacibn. Analizaremos el servidor de la Implementaci6n de Referencia JZEE de Sun como linea debase para examinar estos diversos roles, a medida que vayamos desarrollando una sencilla aplicaci6n bancaria. Tambikn afiadiremos una interfaz Web a nuestra aplicaci6n de fabricaci6n como un mod0 de explorar a1 proceso completo de desarrollo de aplicaci6n JZEE.

Roles de desarrollo y de implernentacion


En capitulos recientes no hemos centrado principalmente en tecnologia EJB, por lo tanto, en este capitulo, ampliaremos el espectro de nuestro estudio y analizaremos algunos puntos generales sobre el desarrollo e implementaci6n de EJB. Tambien daremos algunos pasos utilizando la capa de presentacidn de J2EE con 10s EJB que hemos creado para nuestra aplicaci6n de fabricaci6n. La especificaci6n Enterprise JavaBeans define cinco roles distintos en el ciclo de vida de desarrollo e implementaci6n de una aplicaci6n:
O 0

Proveedor de bean de empresa. Desarrolla componentes EJB. Ensamblador de aplicacion. Combina componentes EJB con otro tipo de software (por ejemplo, programas cliente o componentes Web) para conseguir una aplicaci6n completa. Desplegador. Toma la aplicacibn y la instala en un servidor de aplicacibn, resolviendo cualquier referencia a recursos existentes en el entorno de destino.

0 Vendedor de servidor de aplicacionl contenedor

EJB. Proporcionar el servidor de aplicaci6n en

el que se despliega la aplicaci6n.


0

Administrador del sistema. Gestiona la aplicaci6n despues de que haya sido implementada en un entorno de destino.

Este diagrama ilustra el orden en que deben ser ejecutadas las tareas:

Capitulo 18

Proveedor EJB

,
;

Ensamblador de la apl~cac~on

_ -?

Desplegador

Se~ldor de la apl~cac~onl proveedor del contenedor EJB

f
Admln~strador del slstema

El proveedor EJB es un desarrollador que implementa EJB. El ensamblador tomari 10s EJB (quizis creados por diferentes proveedores) y 10s empaquetari en un archivo J2EE. El ensamblador creari normalmente estos archivos utilizando herramientas proporcionadas por el proveedor de servidor de aplicaci6n. El desplegador tomari entonces 10s archivos y 10s implementari en el senidor. En esta fase del proceso, 10s EJB estin presentes en el servidor per0 todavia n o estin siendo ejecutados. Una vez que el administrador del sistema ha ejecutado cualquier configuracion adicional, puede iniciarse la aplicaci6n.

Estos roles son abstractos en naturaleza y . en un entorno de desarrollo real, se ,. requeririan muchas personas para cada rol o una sola persona realizaria multiples roles.

Estos roles no son el product0 de un proceso o una filosofia concreta de ingenieria de software; en cambio, han crecido de forma natural a partir de objetivos marcados por la tecnologia Enterprise JavaBeans. Comprender 10s roles nos ayuda a comprender la tecnologia y c6mo Csta encaja en un proceso de software de ernpresa, ya sea con cientos de personas trabajando en un proyecto o con una sola persona. Para demostrar estos conceptos, examinaremos mis a fondo la aplicaci6n bancaria que ya hemos introducido. La analizaremos en terminos de divisi6n de trabajo entre varios roles y la haremos menos hipotetica en su naturaleza. Concretamente, analizaremos con detenimiento dos EJB:
0 U n bean de entidad que representa una cuenta 0 U n bean de sesi6n que proporciona un frente interactive a1 bean A c c o u n t

Para proporcionar un ejernplo concreto de la divisi6n de responsabilidades definida en la espe'cificaci6n Enterprise JavaBeans, necesitaremos utilizar un servidor de aplicaci6n. Recorreremos 10s pasos necesarios para crear nuestra aplicaci6n utilizando la Implementacidn de Referencia (RI) J2EE de Sun. La RI es un importante punto de referencia para servidores de aplicacion J2EE y es en su capacidad donde la utilizaremos.

A medida que vayamos avanzando en el ejemplo, exploraremos cada uno de 10s cinco roles, comprendiendo c6mo funciona cada rol y las actividades que realiza.

El proveedor de bean de empresa


La especificaci6n Enterprise JavaBeans proporciona una arquitectura de componentes, lo que sipifica que 10s datos y la 16gica de empresa de una aplicaci6n estin organizados en unidades discretas

938

Roles de desarrollo y de implernentacion


(cornponentes). El proveedor de bean de ernpresa es responsable de proveer componentes EJB. Este "proveedor" puede ser una unica persona o podria ser un equipo de gente forrnado por analistas, prograrnadores y especialistas de sepridad de calidad; el proveedor podria ser incluso un vendedor externo. Los EJB son componentes de software y por ello deberian ser desarrollados con el menor nlimero de dependencias posible en otros EJB o en otros aspectos del proceso de desarrollo. Las interfaces inicial y remota (junto con su documentacian) deben proporcionar u n contrato sujkiente para permitir la construccio'n de las partes dependientes de la aplicacidn. Esto signif;:ca que 10s componentes obtenidos de vendedores externos pueden ser tratados corno una caja negra. El proveedor de bean es normalrnente un experto en 16gica de empresa requerido por una ernpresa y con frecuencia se conoce corno experto de dominio de aplicaci6n. Los EJB que desarrolla en proveedor de bean son norrnalrnente componentes reutilizables que irnplernentan flujo de trabajo, proceso y entidades de ernpresa. El proveedor de bean de ernpresa produce un archivo JAR que contiene archivos relacionados con uno o rnis beans, incluido:
O

La(s) interfaz inicial

O La(s) interfaz rernota y/o local

O Las clases de irnplernentaci6n y cualquier clase que se ajuste


0 Cualquier clase de clave primaria
O U n descriptor de implernentacion (parcialmente cornpleto)

Las clases estin todas situadas en directorios que se corresponden con sus paquetes (un procedimiento estindar par archivos JAR de Java). El descriptor de irnplementacion se ubica en un directorio llamado META- I N F y debe tener el nornbree j b - j a r .x m l . Las interfaces iniciales, las interfaces rernotas/locales, las clases de irnplernentaci6n y las clases de clave prirnaria no estin sujetas a cambio por el ensamblador o el irnplernentador de la aplicacion (y, por supuesto, no serian cambiadas por el vendedor o el adrninistrador del sisterna). Por otro lado, el ensarnblador de la aplicacion cambiari el descriptor de irnplernentacion. (Verernos q u i debe carnbiar exactamente el ensamblador de la aplicaci6n en la siguiente section.) Nuestro entorno de irnplementacion incluiri una herramienta (que puede ser cualquier cosa, desde una utilidad de linea de comando hasta un IDE) que podernos utilizar para construir las partes de un EJB (con la posible exception del descriptor de implernentacion). Mas adelante, utilizaremos herrarnientas proporcionadas por un vendedor especifico de senidor de aplicacion, aunque es posible que un senidor de aplicacion incluya un IDE o que un IDE apoye a multiples senidores de aplicacion. Sin embargo, en cada aplicacion que utiliza EJB, 10s rnetodos de empresa (el cbdigo que representa la esencia completa de la aplicacion) son portitiles. Ademis de las clases Java portitiles y el descriptor de implementation, un servidor de aplicacion tarnbien puede requerir inforrnacion de asociacion: un conjunto de instrucciones referentes a corno debe interactuar la aplicacion con nuestro EJB. Esta inforrnaci6n de asociacion es producida por el implementador y no afecta al codigo que escribimos o a la portabilidad de nuestros componentes. Veamos las interfaces remota e inicial de nuestro ejemplo de aplicacion bancaria. Antes de empezar, Cree la siguiente estructura de directorio:

Capitulo 18

Ernpezarernos con la interfaz rernota para el bean de entidad; guarde este c6digo en s r c \ w r o x \ s o m e ~ i s v \c o r n o A c c o u n t . j a v a :
package import import w r o x . some i s v ;

java.rmi.RemoteException;
javax. e j b . + ;

p l b l i c i n t e r f a c e Account e x t e n d s EJBObject { v o i d withdraw(doub1e amount) throws I r ~ s u f f i c i e r ~ t F u n d s E x c e p t i o r ~ , RemoteException; void d e p o s i t ( d o u b l e amount)


)

throws

RemoteException;

S t r i n g getCustomerType (

throws

RemoteException;

I
~ s t es a la interfaz inicial para el bean de entidad; guirdela c o r n o ~ c c o u n t ~ o mjea v a en src\wrox\some~isv\:
package import import p u b l i c i n t e r f a c e A c c o u n t H o m e e x t e n d s EJBHome { p u b l i c Account c r e a t e ( i n t a c c o u n t I D , S t r i r l g customerName, Strirtg customerType, double i n i t i a l B a l a n c e ) throws CreateException, RemoteException; publ ~ c Account findByPrlmaryKey ( I n t e g e r accountID) throws FinderException, RemoteException; wrox.same isv;

~ s t es a la interfaz rernota del bean de sesi6n; guirdela c o r n o A c c o u n t M a n a g e r j a v a en src\wrox\some~isv\:


package import import wrox.some isv;

javax.ejb.*;

java.rmi.RemoteExceptior~;

p u b l i c i n t e r f a c e AccountManager e x t e n d s EJBObject { v o i d c r e a t e A c c o u n t ( i n t a c c o u n t I D , S t r i n g customerName, S t r i n g customerType, double i n i t i a l B a l a n c e ) t h r o w s NoAccountCreatedException, R e m o t e E x c e p t i o n ; v o i d w i t h d r a w ( i n t a c c o u n t I D , d o u b l e amourit) t h r o w s I r ~ s u f f i c i e r ~ t F u r ~ d s E x c e p t i oN r~ o, SuchAccour~tExceptior~, RemoteException; v o i d d e p o s i t ( i n t a c c o u n t I D , d o u b l e amount ) throws NoSuchAccountException, RemoteEsception; public void cancel ( i n t accountID) throws RemoteException;

Roles de desarrollo y de irnplementacion


La interfaz inicial para el bean de sesibn es asi; guirdela cornoAccountManagerHome . j a v a en src\wrox\some~isv\:
p a c k a g e wrox.sorne import import
j avax. ej b.

isv;

*;

java.rmi.RemoteException;

p u b l i c i n t e r f a c e A c c o u n t M a r ~ a g e r H o m e e x t e n d s EJBHome { AccountManager c r e a t e ( ) throws C r e a t e E x c e p t i o n , RemoteException;

I Finalmente, estas son las clases de exception que necesitarnos; gudrdelas todas en src\wrox\some~isv\cornoInsufficientFundsException.java:
package wrox.sorne isv;
{

p u b l i c c l a s s I n s u f f i c i e r ~F t undsException e x t e r ~ d sException p u b l i c I n s u f f i c i e n t F u r ~ d s E x c e p t i o (r ) ~ 1I

I
NoAccountCreatedException.java:
package wrox.sorne isv;
{

p u b l i c c l a s s NoAccOuntCreat e d E x c e p t i o n e x t e n d s E x c e p t i o n p u b l i c NoAccountCreatedException ( S t r i n g r e a s o n ) { s u p e r ( reason ) ; 1 p u b l i c S t r i n g getReason return getMessage0; 1


( )

package

wrox.some

isv; Exceptior~ {

p u b l i c c l a s s NoSuchAccour~tException e x t e n d s p u b l i c N o S u c h A c c o U r ~ t E ~ c e p( t ) i ~ i~I ~

Para que nuestro componente sea portitil, debe evitar cualquier dependencia de un entorno concreto de implernentaci6n, corno utilizar una implernentaci6n de seguridad de propiedad. Es ficil mantener una interfaz sencilla separada de un entorno de implernentaci6n, por lo que no debe sorprendernos que nuestras interfaces inicial y remota no introduzcan ninguna dependencia concreta. Las clases de implernentacibn proporcionan una prueba mis dura. Hay todo tip0 de oportunidades para crear dependencias en una deterrninada irnplernentacion de seguridad, una base de datos concreta o un deterrninado conjunto de requisites para cornportarniento transactional. Las reglas que irnpone la especificacibn Enterprise JavaBeans sobre el desarrollador de bean estin disefiadas para reducir estas dependencias. Para cornprender como funciona, resulta util considerar 10s principios fundarnentales de las funciones de la tecnologia EJB. Una de las principales ventajas de utilizar tecnologia EJB es que proporciona un entorno abstract0 para programacibn de logica de ernpresa, libre de problernas sobre temas de nivel de sisterna o de entorno de destino. Consecuenternente, el contenedor EJB se interpone en llarnadas de metodo de ernpresa. Es decir, intercepta la Ilarnada, realiza las comprobaciones de seguridad, inicia o retoma las transacciones segun sea necesario, crea el entorno y entonces envia la solicitud a1 verdadero rnktodo de ernpresa.

Ahora, la hltima pieza del puzzle: la relacion fundamental entre 10s roles de desarrollador EJB/ ensamblador de aplicacion y el product0 finalizado, en ejecucion es la indirecci6n. La indireccion es el uso de un "soporte de espacio" en su codigo Java o descriptor de implementacibn, en lugar de una referencia a una verdadera entidad del entorno de implementacion. Si comprendemos estas tres cosas (abstraction, interposition e indireccion) 10s detalles encajarin sin problema. Esta indireccion tiene lugar en dos niveles: el del EJB y el de la aplicacibn. Para comprender la diferencia, imagine que tenemos un bean de cuenta bancaria que utilizar un metodo i s c a l l e r I n R o l e ( ) para determinar si el llamante esti utilizando 10s permisos de un cajero automltico (siglas AMT). (Veremos M , en el siguiente pronto un ejemplo de esto). El bean puede tener un nombre de rol refundido ~ ~ A T como codigo:
if a m o u n t > 2501 & & a c c o u n t . g e t C u s t o m e r T y p e ( ) . e q u a l s ( C u s t o m e r T y p e s . INDIVIDTJAL) & & c t x . i s C a l l e r I n R a l e ("ATM" 1 ) { t h r o w rlcw S e c u r i t y E x c e p t i o n ( ) ;
( (

Sin embargo, este nombre de rol refundido puede no ser coherente con el sistema de seguridad de otros EJB de nuestra aplicaci6n. Podemos haber adquirido este bean de gestion de cuenta de vendedor independiente de software y querer combinarlo con otros EJB que hemos escrito o adquirido de otras fuentes. C o m o resultado, la especificacion proporciona un nivel de indireccion en el nivel EJB. Asociamos esta referencia de rol en el EJB a un rol de seguridad definido en el descriptor de implementacion. Si nuestro sistema de seguridad define un rol llamado U n m e d i a t e d A c c e s s que hace referencia a1 acceso desde la Web o desde un cajero, la asociacidn podria tener este aspect0 (el codigo completo para este EJB y para el descriptor de implementacion estl m l s adelante):
<security-role> <description> T h i s r o l e i s p e r f o r m e d b y a n y a c c o u n t a c c e s s i n which a b a n k i s n o t - i n v o l v e d , s u c h a s an I r ~ t e r r z e t t r a n s a c t i o n o r A T M withdrawal. </description> <rol e-r~ame>UnmediatdAccess</r01e-r~arne> </security-role\

employee

Si estamos escribiendo nosotros mismos todos 10s EJB y combinlndolos en una aplicacion para nuestro propio uso, esta indireccion constante puede pareccr innecesaria. Podriamos simplemente utilizar el nombre del r o l ~ n m e d i a t e d ~ c c e en s s nuestro EJB y librarnos de este < s e c u r i t y - r o l e - r e f > especifico del bean. Sin embargo, el sistema esti disefiado para maximizar la portabilidad el cbdigo y la reutilizacion de cada EJB. Existen tres tipos de referencia que puede codificar un proveedor EJB y que debe ser declarada en la parte especifica del bean del descriptor de implementacibn:
O Referencias a otros EJB O Referencias a recursos (como una conexion JDBC) O Referencias a roles de seguridad

Siempre que utilicemos cualquiera de estas referencias en nuestro codigo, debemos pensar en ellas como en referencias "virtuales". Podemos desarrollar nuestro EJB sin preocuparnos por 10s detalles sobre que deberia referenciarse; por ejemplo, la asociacion especifica de fuente de datos que debemos utilizar, 10s roles de seguridad que existirin en la aplicacion ensamblada o el nombre final de implementacion J N D I de un EJB concreto. Debemos, sin embargo, proveer en el descriptor de implementacion un < s e c u r i t y r o l e - r e f > , u n < r e s o u r c e - r e f > o u n < e j b - r e f > . H e m o s e n c o n t r a d o e s t o s tipos dereferenciaen

Roles de desarrollo y de implernentacion


10s capitulos anteriores. Cuando hemos desarrollador un EJB que utilizaba una conexi6n de base de datos, otro EJB o un rol de seguridad, hemos declarado el uso de ese recurso en el descriptor de implementaci6n.

U n elemento < r e s o u r c e - r e f > describe una referencia de recurso utilizada en el cddigo Java del EJB. Tiene un sub-elemento optional description y tres sub-elementos obligatorios: < r e s - r e f - n a m e > , < r e s - t y p e > y < r e s - a u t h > . El e l e m e n t o < r e s - r e f - n a m e > contiene el nombre que utiliza el c6digo de implementaci6n de Java para buscar el recurso en el contexto JNDI de 10s EJB. El elemento < r e s t y p e > contiene el tip0 Java de la factoria de conexion utilizada para obtener acceso a una conexi6n de recurso. Los tipos estindar son:
0
0

j a v a x . s q l .D a t a S o u r c e paraconexiones JDBC

javax.jms.QueueConnectionFactoryyjavax.jms.TopicConnnectionFactorypara conexiones JMS


j a v a x . m a i l . S e s s i o n para conexiones JavaMail

0
0

j a v a n e t . U R L para conexiones URL


j a v a x r e s o u r c e . c c i .C o n n e c t i o n F a c t o r y para Conectores Java a sistemas de legado

El elemento < r e s - a u t h > permite a1 desarrollador EJB indicar si el contenedor o el desarrollador EJB proporciona un nombre y una contrasefia para la conexi6n. Los valores vilidos son A p p l i c a t i o n o c o n t a i n e r . Este es un ejemplo de un e l e m e n t o < r e s o u r c e - r e f > en el descriptor:

Este declara una fuente de datos llamada j d b c / s h i p D B . Cuando se implemente el EJB, el contenedor hari disponible este recurso en el entorno, permitiendonos encontrarlo en el siguiente c6digo:
Context initialContext DataSource datasource env/jdbc/shipDBN) ;
=
=

new InitialContext ( ) ; DataSource) initialContext. lookup ( " java: camp/

Observe que este cddigo esti destinado a funcionar el servidor (por ejemplo en la clase EJB). Si queremos ejecutar el mismo tip0 de operacibn para un cliente, tendremos que crear un contexto inicial diferente. Para el Servidor WebLogic, el mod0 adecuado para inicializar un contexto cliente es el siguiente:
Properties prop = new Properties ( ) ; prop.setProperty(Cor~text.INITIAL CONTEXT FACTORY, ; "weblogic. jndi .WLInitialCor~textFactory"J prop.setProperty(Coritext.PR0VIDER URL, "t3://localhost:7001"); Context initialcontext = new InitialContezt (prop);

U n elemento < e j b - r e f > describe una referencia a otro EJB utilizado en el cbdigo Java del EJB. Tiene un sub-elemento opcional<des c r i p t i o n > , un sub-elemento opcional<e j b- l i n k > ycuatro sub-elementos obligatorios:<e j b - r e f - n a m e > , < e j b - r e f - t y p e > , < h o m e > y < r e m o t e > . Elelemento<ej b - r e f name> contiene el nombre que utiliza el cbdigo de implementaci6n para buscar el EJB en su contexto JNDI. El elemento < e j b - r e f - t y p e > indica el tip0 de bean, cuyos valores vilidos son E n t i t y y s e s s i o n .

Capitulo 18
Los beans controlados por mensaje no tienen interfaz inicial y rernota pero, en su lugar, reciben mensajes asincr6nicos. Para comunicar con u n bean controlado por mensaje, se utilizaria una referencia de recurso para u n t6pico o cola.
El elernento <home> indica el nornbre de clase cualificado cornpleto de la interfaz inicial del EJB referenciado. El elernento < r e m o t e > indica el nornbre de clase cualificado cornpleto de la interfaz rernota del EJB referenciado. La referencia opcional < e j b-link> puede contenedor un nornbre EJB, que indica una irnplernentaci6n EJB concreto a1 que debe referirse este < e j b - r e f >. El siguiente fragment0 de un descriptor de irnplernentaci6n ilustra c6rno podernos utilizar < e j b - r e f >. En este ejernplo, nuestro EJB M a n a g e o r d e r s necesita acceder a un EJB O r d e r s . Por lo tanto, declararnos lo siguiente en la s e c c i 6 n ~ a n a g e 0 r d e r sde nuestro descriptor: <ejb-ref> < e jb - r e f - n a m e > e j b / O r d e r < / e j b-ref-r~arne> < e j b - r e f -type>EntityC/ejb-ref-type>
chorne>factory.order.OrderHorne</horne>

-:rernote>f a c t o r y . o r d e r . O r d e r < / h o m e > < e ] b - l i r ~ k > O r d e r s . : : / eb j- l i n k > < / e jb - r e f > Nuestro EJB M a n a g e o r d e r s puede ahora referenciar el EJB O r d e r s con el siguiente c6digo: OrderHorne h o m e = (OrderHome) j a v a x . r m i . PortableRernoteObj e c t . n a r r o w ( i n i t i a l . l o o k u p ("java:comp/erv/ejb/Order"), 0rderHorne.class);

El elernento < e j b - l o c a l - r e f > se utiliza para referenciar un EJB a1 que accede a travks de sus interfaces local y rernota. Aparte de esta diferencia, la semintica es similar a < e j b - r e f >. El implementador crea una asociaci6n entre recursos reales (corno conexiones de bases de datos) y 10s soportes de espacio de referencia de recurso enurnerados en el descriptor de irnplernentaci6n. Por supuesto, si es obvio qu6 significa un deterrninado soporte de espacio, un servidor de aplicaci6n inteligente puede hacer esta asociaci6n sin solicitar rnis inforrnaci6n. Por ejernplo, si s61o hay un tip0 disponible de conexi6n de base de datos, todas las referencias de recurso de base de datos deben asociarse a ese tipo. Junto con esta indirecci6n de nivel EJB, tarnbih hay indirecci6n de nivel de aplicaci6n. El rol de seguridad que referencia un deterrninado EJB con el metodo i s C a l l e r I n R o l e ( ) esti vinculado a un rol de nivel de aplicaci6n declarado en el descriptor. Pero este rol de nivel de aplicaci6n es todavia una abstraccibn, no un verdadero objeto de sisterna de seguridad del rnundo real. Para ser independiente del sisterna operativo subyacente, J2EE introduce el concept0 de un principal. U n principal es un simple nornbre que se utiliza para deterrninar 10s privilegios de un usuario. Puesto que esto es una abstracci6n JZEE, todavia es necesario que haya una asociacion de este principal al nornbre utilizado en el sisterna operativo subyacente para deterrninar el nivel de seguridad. Esta indirecci6n se resolveri finalrnente en el period0 de irnplernentacion. Considere la indirecci6n para nuestro rol de ATM que hernos referenciado. El rol de seguridad de ATM hace referencia a1 rol de seguridad U n m e d i a t e d A c c e s s , que seri ernparejado durante el periodo de irnplernentaci6n a uno o rnis grupos reales o principales en alguna irnplernentaci6n de seguridad. N i el desarrollador de bean no el ensarnblador de la aplicaci6n tiene que preocuparse por la irnplernentacion de seguridad.

Roles de desarrollo y de implernentacion

v
Pr~nc~pal real

O t r o ejemplo de una indirecci6n similar en un EJB que referencia en cddigo a un objeto JDBC c o n n e c t i o n . El EJB podria utilizar un nombre arbitrario para referirse a la conexi6n JDBC, sin considerar el resto del entorno de aplicaci6n o de implementaci6n. Durante el periodo de implementaci6n, este nombre arbitrario seria asociado a una factoria de conexi6n D a t a s o u r c e que esti asociada a1 espacio de nombre del s e n i d o r de aplicaci6n. Esta es nuestra clase de implementaci6n para el bean de s e s i 6 n A c c o u n t ~ a n a g e r Utiliza . dos referencias que deben ser declaradas: una a un rol de seguridad y otra a1 bean de e n t i d a d ~ c c o u n tC . o n prop6sitos de demostraci6n, hacemos pleno uso de la indirecci6n utilizando diferentes nombres para el rol y el bean:
package import import import wrox.some

isv;

ja v a x . e l b . * ; ja v a x . naming. * ; java.rmi.RemoteException;
implemerjts SessionBean
[

p u b l i c c l a s s AccountManagerEJB public SessionContext ctx; public void createAccount ( i n t

accountID, S t r i n g Stl-lng customerType, t h r o w s N o A c c o u n t ~ ~ r e a t e d E x c e p t i o n{

customerName, double initialBalance)

t1.Y i AccountHome accountHorne = getAccountHome ( ) ; accourltHome. c r e a t e ( a c c o u r l t I D , customerName, c u s t o m e r T ype, initialBa1ance) ; 1 catch (CreateException c e ) { t h r o w new N o A c c o u r ~ t C r e a t e d E x c e p t i o i rc ~e . g e t M e s s a q e ( ) 1 ; j catch !Rimc~teExceptior~ re) { t h r o w r ~ e w E J B E x c e p t i o n ( r e );

I
p l ~ b l i cv o i d try withdraw ( i n t accountID, double amount) t h r o w s I r ~ s u f f i c i e n t F u r ~ d s E x c e p t i o rN ~o , SuchAccour~tExce~~tio { r~
=

1
Accour~t accourjt if ((amount
&& &&

j e t A c c o u n t ( a c c o u n t I D );

> 2501

throw

a c c o u r ~ tq . e t C u s t o m e r T y p e ( ) . e q u a l s ( C u s t o m e r T y p e s . INDIVIDUAL) c t x . isCallerIr~Role("ATM") ) { rlew S e c u r i t y E x c e p t i o n ( ) ;

I
1

a c c o l ~ r t. t w i t h d r a w ( a m o u n t ); catch (RemoteException r e )

throw

new

E J B E x c e p t i o n ( r e );

i
pub1 i c void d e p o s l t ( i n t accountID, double t h r o w s NoSuchAccountException amount)
{

try I Account account = getAccount ( a c c o u n t I D ); a c c o u n t . d e p o s i t (amount) ; 1 c a t c h (RemoteException r e ) { t h r o w new E J B E x c e p t i o n ( r e ) ;


I

public void c a n c e l ( i n t accuuntID) { try i Account a c c o u n t = getAccount ( a c c o u n t I D ); a c c o u n t . remove ( ) ; ) c a t c h ( N o S u c h A c c o u r ~ t E s c e p t i c ~n rs ~a e ) ( / / b i e r , , ya e s t i h e c h o 1 catch [Exception e ) { t h r o w new E J B E z c e p t i o n ( e ) ;

i
p r i v a t e Account getAccount i i n t accountIU) throws NoSuchAccour~tException { try { A c c o u n t H o m e home = g e t A c c o u n t H o m e ( ) ; r e t u r n home. f i n d B y F r i m a r y K e y ( n e w I n t e g e r ( a c c o u n t I D )) ; ) c a t c h (RemoteEsception r e ) { t h r o w new E J B E s c e p t i o n ( r e ) ; ) catch (FinderExcepticn f e ) { t h r o w new N o S u c h A c c o u r ~ t E x c e p t i o r (~ ) ;

p r i v a t e AccountHome getAccountHome [ ) { try I I n i t i a l C o n t e x t i n i t i a l = new I n i t i a l C c , n t e x t ( ) ; A c c o u r ~ t H o m e home = ( ( AccountHome) j a v a x . rmi . P o r t a b l e R e m , 3 t e O b je c t . r ~ a r r o w i r ~ i t i a llookup . ( " j a v a : comp/env/ej b/GenericAccc?unt" ) AccountHome. c l a s s ) ; r e t u r n home; } c a t c h (NamingException n e ) { t h r o w new E J B E x c e p t i o n ( n e ) ;

public void ejbCreate() ( 1 public void ejbActivate ( ) ( ) public void ejbPassivate( ) { i p u b l i c void ejbRemove() { j public void setSessionContext (SessionContext c t x ) this.ctx = ctx;

r st as son las declaraciones de recurso relevantes del descriptor de implementaci6n e j b- j a r .xrnl para la
fase de desarrollo EJB y la fase de ensamblaje de la aplicaci6n:
<ejb-ref>

Roles de desarrollo y de irnplementacion


. e j b - r e f - r ~ a r n e ' e j b / G e r > e r i c A c c o u r i t< / e j b - r e f - r t a m e > c e j b - r e f - t y p e > E r ~ t i t y < / eb j -ref -type> c h i . m e > w r o x . s o m e i s v . A c c o u n t H r m e < / home> crernote>wrox.some i s v . A c c o u r ~ t < / r e m o t e > < e jb - l i n k > A c c o u n t < / e j b - 1 i r 1 k > </ejb-ref> <security-role-ref> <description> T h i s r o l e r e f e r s t o automated c u s t ~ m e rw i t h d r a w a l s f rom t h e a c c o u n t ; n o b a n k i n t e r m e d i a r y i s i n v o l v e d . </description> <role-riamsiATM</role-rlame> <role-link>Ur~mediatedAci:ess</role-lir~k> </security-role-ref>

Un bean de entidad que utilice persistencia gestionada por contenedor puede proporcionar automiticamente otro tip0 de indirection: la asociaci6n de 10s datos de estado del bean a campos en un almacen persistente. Nuestro bean de cuenta tiene cuatro campos de datos de este tipo: a c c o u n t I D , c u s t o m e r N a m e , c u s t o m e r T y p e y a c c o u n t B a l a n c e . Estos campos podrian asociarse a campos con cualquier nombre en una tabla en cualquier tip0 de base de datos y (dependiendo de 1as capacidades de asociacion objeto/relacional de nuestro servidor de aplicacion) podrian tambien asociarse a campos de diferentes tablas. Si nuestro servidor de aplicaci6n y controlador JDBC son compatibles con las realizaciones distribuidas de dos fases, incluso podrian asociarse a campos de diferentes bases de datos. Esta capacidad es especialmente importante cuando las aplicaciones EJB deben coexistir con datos de legado.
ES la clase de irnplementaci6n para el bean de e n t i d a d ~ c c o u n tObserve . que proporcionamos flexibilidad para nuestro bean en forma de parimetro de entorno. En la prictica, esta parte de informacih (el saldo minimo de la cuenta) pertenece a una base de datos donde puede ser modificada sin volver a implementar el bean; la tecnica que estamos utilizando es generalmente aplicable a informaci6n mis estable:

package lrnport import publlc

w r o x . some i s v ; j a v a x . e j b . +; j a v a x . r ~ a r n i r ~* q;. abstract class A c c o u r ~ t E J B implements EntltyBear~ {

public public public public public public

abstract abstract abrtract abstract abstract abstract

i n t getAccnuntID( ) ; v o i d ~ e t A c c o u r ~ t I iD n (t

a c c o u r ~ t I P; )

S t r i r l q getCustomertlame ( ) ; v o i d s e t C u s t o m e r N a r r ~[ t S t r i n g customerName) ; S t r i r ~ yg e t r ' u s t c m e r T y p e ! ) ; void seti'ustamerType(String

customerType);

public abstract ~81lblic abstrac:t

double qetAccountBalanct ( ) ; vi'id setAcci>~lntBalanc (e ,d,;uble a c c o u n t B a l a n c e ) ;

p u b l i c v ? i d d e p i j s i t (tdi.l.~bleamount ) { s e t A c c ~ ~ u r ~ t B a l a(ngceet A c c c ~ i ~ r ~ t B a l aI r) c e+

amrunt) ;

Capitulo 18

public

Integer

e j b C r e a t e ( i n t a c c o u n t I D , S t r i n g customerName, S t r i n g customerType, double i n i t i a l B a l a n c e ) throws CreateException {

if

(!customerType.equals(C~~stomerTypes.CORPORATION) &&!customerType.equa1s(CustomerTypes.INDIVIDUAL)) I
throw new C r e a t e E x c e p t i o n ("Unknown customer type.") ; called");

I
S y s t e m . o u t . p r i n t l n ("Accour1t. e j b C r e a t e ( ) d o u b l e minimumBalarlce = getMirlimumBalance ( ) ; i f ( i r ~ i t i a l B a l a n c e< m i n i m u m B a l a n c e ) { t h r o w new C r e a t e E x c e p t i o n ("Minimum b a l a n c e r e q u i r e d . " ) ;

1
s e t A c c o u r ~ t I D ( a c c o u r ~ t I; D)

setCustomerName(customerName); setCustomerType(customerType);
s e t A c c o u n t B a l a n c e ( i r ~ i t i a l B a 1 a r i c e; ) r e t u r n new I n t e g e r ( g e t A c c o u n t I D ( )) ;

1
public void e j b P o s t C r e a t e ( i n t a c c o u n t I D , S t r i n g customerName, S t r i n g customerType, double i n i t i a l B a l a n c e ) throws CreateException { )

p r i v a t e d o u b l e getMinimumBalance ( ) [ try 1 I n i t i a l C o n t e x t i n i t i a l = new I n i t i a l C o n t e x t ( ) ; Double minimumBalance = ( D o u b l e ) i n i t i a l . l o o k u p ( " j a v a : c o m p / e r ~ v / m i r ~ i m u m B a l a r ~ c; e") r e t u r n minimumBalar~ce.doubleValue ( ) ; ] c a t c h (NamingException n e ) { t h r o w new E J B E x c e p t i o n ( n e ) ;

I
public public public public public public public void void void void void void void ejbActivate ( ) { I ejbLoad0 { I e jbpassivate ( i { 1 ejbRemove ( ) I ejbstorei) { 1 s e t E n t i t y C o r ~ t e x( tE r ~ t i t y C o r i t e x tc t x ) u n s e t E r ~ t i t y C o n t e x (t ) { ]
J ,

[ ]

La clase final de implementacidn es una simple interfaz que proporcionar algunas constantes de cadena. (Idealmente, pondriamos estas constantes en un paquete separado de nuestro EJB de modo que varios beans pudieran utilizarlas.)
package w r o x . some i s v ;

p u b l i c i n t e r f a c e CustomerTypes { p u b l i c s t a t i c f i n a l S t r i n g CORPORATION = " c o r p o r a t i o n " ; p u b l i c s t a t i c f i n a l S r r i r ~ g INDIVIDUAL = " i n d i v i d u a l " ;

U n descriptor de implementacidn es el repositorio de informacidn sobre 10s EJB de una aplicacidn. Las herramientas del servidor de aplicacidn utilizarin esta informacidn para comprender quk instancias de indireccidn necesitan ser resueltas en el period0 de implementacidn. Hemos examinado partes pequefias del descriptor de implementacidn aisladas mientras analizibamos otras caracteristicas de la tecnologia EJB y ahora ha llegado el momento de examinar el descriptor de implementacidn en su conjunto.

948

Roles de desarrollo y de implementacion


Hay dos tipos de informaci6n contenida en un descriptor de implementacion:
0 Informaci6n estructural relacionada con determinados EJB.

Este tip0 de informacion se relaciona con el c6digo Java que ha creado el proveedor del bean, como nombres de clase cualificados completes, referencias utilizadas y tip0 de demarcation de transaccion (gestionada por contenedor y gestionada por bean).
0 Informaci6n de ensamblaje de la aplicacidn

Describe c6mo 10s EJB de una JAR son compuestos en una unidad mayor de implementacion de aplicacion. Ejemplos de este tip0 de informacion podrian ser la definicion de roles de seguridad y permisos de mktodo, asociaciones de referencias de bean de empresa a otros beans o la definicion de atributos de transaccion en mktodos. El elemento raiz del descriptor es < e j b - j a r > y existen dos elementos por debajo de 61:
0 < e n t e r p r i s e - b e a n s > contiene informacion estructural relevante para determinados EJB
0 < a s s e m b l y - d e s c r i p t o r > contiene informacion sobre como 10s EJB estin compuestos en una

unidad mayor de implementacion de aplicacion Es bastante probable, incluso posible, que la misma persona o personas que estin desarrollando EJB Sean tambien responsables de ensamblarlos en una aplicacion. En este caso, la division de responsabilidades entre el desarrollador de la aplicacidn y el ensamblador de la aplicacidn puede parecer irrelevante. Sin embargo, tendiendo en cuenta la reutilizacion y la reventa de componentes por parte de Vendedores Independientes de Software (ISV), la especificacion EJB especifica claramente quikn es responsable de quk entradas en el descriptor e incluso indica quk entradas pueden ser especificadas por el desarrollador de bean y quk entradas pueden ser modificadas posteriormente por el ensamblador de la aplicacion. Por lo general, el desarrollador de bean es responsable de las entradas que dependen del elemento < e n t e r p r i s e b e a n s > y el ensamblador de la aplicacion es responsable de las entradas secundarias del elemento < a s s e m b l y - d e s c r i p t o r > , aunque hay ciertas excepciones. De acuerdo con la especificacion, el proveedor debe garantizar que el descriptor de implementation contiene la siguiente informacion para cada bean:
0 Tipo de EJB: sesi6n o entidad

El e l e m e n t o < s e s s i o n > o < e n t i t y > dependeridirectamente del e l e m e n t o < e n t e r p r i s e beans>.


0 Nombre de EJB

~ s t es e s610 un mod0 de identificar el EJB. El nombre no guarda ninguna relacion con el nombre J N D I bajo el que sera implementado el EJB o travks del cual podrin acceder 10s clientes a1 EJB, ni tampoco tiene relacion con el nombre que utilizarin otros beans para encontrar este bean. El proveedor de bean especifica el nombre en el elemento < e j b-name> y este nombre debe ser exclusivo en el mismo archivo (JAR o EAR).
0 La clase de implementaci6n de EJB

El nombre de la clase Java cualificado completo de la clase de implementation del bean de empresa se especifica utilizando el elemento<ej b - c l a s s > .
0 Las interfaces EJB inicial y remota

El proveedor del bean debe especificar el nombre cualificado completo de las interfaces inicial y remota del bean de empresa en el elemento <home> y 10s elementos <remote>.

o Si u n bean de entidad es o n o reentrante


Se utiliza el elemento < r e e n t r a n t > , con un valor de T r u e o F a l s e . (Los beans de sesion nunca son reentrantes.)

Capitulo 18
O Si u n bean de sesi6n tiene o no tiene estado Se utiliza el elernento <session-type>, con un valor de Stateful o Stateless.
0

Si u n bean de sesi6n gestiona o no sus propias transacciones Se utiliza el elernento <transaction-type>, con un valor de Bean o Container. Si un bean de entidad utiliza BMP o CMP Se utiliza el elernento <persistence-type> con un valor de Bean o Container.

O Clase de clave primaria del bean de empresa El nornbre de la clase Java cualificado cornpleto de una clase de clave prirnaria del bean de entidad es especificado utilizando el elemento <prim-key-class >. Tkcnicarnente, esto s61o es obligatorio para un bean de entidad con persistencia gestionada por bean. Si su clave prirnaria se asocia a varios campos, necesitari especificar una clase Java en esta etiqueta y la clase (que habitualmente terrnina en "PK", por ejernplo, SportPK) contendri todos 10s carnpos necesarios para identificar exclusivarnente su EJB.
0

Campos gestionados por contenedor Si el bean de ernpresa en un bean de entidad con persistencia gestionada por contenedor, 10s carnpos gestionados por contenedor deben ser enurnerados utilizando elernentos <crnp-field>. Esquema abstract0 De nuevo para utilizar persistencia gestionada por contenedor, debe haber un elernento <abstractschema> para asociaciones corno Q L EJB. Entradas de entorno Utilizando el elernento <nev-entry>.

a a

O Gestores de recursos Si hay alguna referencia de factoria de conexion de gestor de recursos en el c6digo Java, como una referencia JDBC Datasource.

Referencias de EJB Cualquier referencia en el c6digo a otros EJB.


Cualquier referencia en el c6digo a roles de seguridad.

0 Referencias de seguridad

Recuerde que esta inforrnaci6n se especificara habitualrnente utilizando una herrarnienta, per0 el descriptor de irnpjernentacion es sencillarnente un archivo XML que puede ser editado rnanualrnente si asi lo desearnos. Este es el descriptor producido por el desarrollador de bean. (Recuerde que Cste no es el product0 cornpleto que irnplernentarernos, puesto que el ensarnblador de la aplicacion tarnbiin lo editara.)

<!DOCTYPE JavaBearls

ejb-jar PUBLIC ' - / / S u r ~ M i c r o s y s t e m s , Ir,c.//DTD Enterprise 2 . O//EN1 'http://java.sun.com/dtd/ejb-jar 2 O . d t d l \

El nornbre, el tip0 de gesti6n de estado, las clases Java y el tip0 de transacci6n del bean
AccountManager:

Roles de desarrollo y de implernentacion

Declarar nuestro uso de una referencia a otro EJB:

Declarar nuestro uso de un rol de seguridad:


<security-role-ref> <description> This role refers to automated customer withdrawals from the account. No bank intermediary is involved. </description> <role-name>ATM</role-name> </security-role-ref> <security-identity>
<description></description>

<use-caller-identity></use-caller-identity> </security-identity> </session>

El nombre, el tip0 de persistencia, las clases Java (incluido la clase de clave primaria) y la capacidad de reentrada del b e a n ~ c c o u n t :
<entity>
<display-name>Accourit</display-name>

<ej b-name>Account</ej b-name> <home>wrox.some isv.AccountHome</home> <remote>wrox.some isv.Account</remote> <ejb-class>wrox.some isv.AccountEJB</ej b-class>
<persister~ce-type>Cor~tair~er</persisterLce-type>

<prim-key-class>java.lar1ggIr1teger</prim-key-class> <reentrant>False</reer~trarit>

La declaraci6n de 10s campos para persistencia gestionada por contenedor:

Capitulo 18
La declaraci6n de una entrada de entorno:
<env-entry>

<er~v-er1try-r~ame>mir1imumBa1ar1ce</er~v-er1t~-~~-r~ame>
<er~v-entry-type> j a v a . I a n g . D o u b l e < / e r ~ v - e n t r y - ty p e > <er~v-entry-value>l50.O</er1v-er~try-va1ue> </env-entry> <security-identity> <description></descriptior~> <use-caller-identity></use-ca11er-ider~tity~~ </security-identity> </entity> </enterprise-beans> </ejb-jar>

El ensamblador de la aplicacion
El ensarnblador de la aplicacion cornbina uno o rnis archivos JAR EJB (que son la produccidn del desarrollador del bean) en una aplicaci6n. Esto significa que el descriptor de irnplernentaci6n XML debe ser editado de rnodo que la inforrnacibn de nivel de aplicacion (corno roles de seguridad y referencias entres beans) pueda ser afiadida. El ensarnblador de aplicacion puede, en esta fase, afiadir tarnbien otros tipos de cornponentes de aplicaci6n corno servlets, piginas JSP o aplicaciones cliente. El ensarnblador de aplicacion no necesita cornprender la irnplernentaci6n de 10s EJB per0 si necesita cornprender las interfaces inicial y rernota, y la 16gica de ernpresa que representan 10s rnetodos en el EJB. En nuestra aplicaci6n bancaria, el ensamblador de aplicacidn tiene dos roles:
0

Cornpletar la edicion del descriptor de irnplernentaci6n. funcionalidad de 10s cornponentes de lado servidor (una aplicaci6n real necesitaria obviarnente una interfaz cliente real para la funcionalidad de ernpresa que proporcionarin 10s cornponentes de servidor).

LI Proporcionar algunas aplicaciones cliente. Estas aplicaciones cliente sirnplernente probarin la

S e g h la especificaci6n, la siguiente inforrnaci6n del descriptor de irnplernentaci6n es relevante en esta etapa del desarrollo de EJB:
0

El ensarnblador de aplicaci6n puede utilizar el elernento<e j b-link> para indicar que EJB de un archivo JAR debe ser asociado a una referencia de bean de ernpresa declarada por un EJB en la secci6n<enterprise-beans> El ensarnblador de aplicaci6n puede definir uno o rnis roles de seguridad El ensarnblador de aplicaci6n puede definir perrnisos de metodo EJB a un rol de seguridad que haya definido

LI El ensarnblador de aplicaci6n debe vincular cualquier referencia de rol de seguridad declarada por un

U Si el EJB utiliza transacciones gestionadas por contenedor, el ensarnblador de aplicaci6n debe

definir las propiedades transaccionales de 10s rnetodos de ernpresa definidos en las interfaces inicial y rernota del EJB Adernis, la siguiente inforrnaci6n que ha sido provista por el desarrollador de EJB puede ser rnodificada:
O

El nornbre del esquerna abstract0 de EJB. Este elernento es nuevo en EJB 2.0 y solo es necesario que lo rnencionernos si varnos a utilizar instrucciones de Lenguaje de Consulta Enterprise JavaBeans (QL-EJB) que referencien este EJB.

Roles de desarrollo y de implernentacion


o Los valores de las entradas de entorno.
O El campo de descripci6n para cualquier entrada.
~ s t es a la versi6n final del descriptor de implementaci6n de nuestra aplicaci6n:

< ! DOCTYPE JavaBearls

ejb-jar PUBLIC ' - / / S u r t M i c r i r s y s t e m s , I n c . //UTD E n t e r p r i s e I. O//EN' 'http://java.suri.c,,rn/dtd/ejb-jal-- 2 - O . c i t d f ?

,<ejb-jar> <dis~lay-nams>ISVs'/<iisplay-r~ame? <enterprise-beans> <session .

<dis~,lay-name>Accour~tMar~iiger</di.cplay-r~ame>
< e j b - n a m e > A c c u u n t M a r 1 a q e r ~ . / ej b-name> h;,me> / / h , i m e > w r o x . s<,me- i s v . R c c o u n t M a r ~ a g e r H u m e ~ e/ i ~ - e m ~ ~ t e > w some r o x .-i s v . A c c o u n t M a r ~ a g e r < / r e m r i t < e j D - c l a s s > w r o x . some - i s v . A c c o u r ~ t M a n a g e r E J B < / e j b - c l a s s >

<sessic)rs-ty~~e>State1tsst/se.ssic~r~-type> <trar~sactinn-type>Contairier</trar~.-actif,rl-type>

El elemento < e jb-ref> se vincula ahora con el bean A c c o u n t :


<ejb-ref, < e jb - r e f - n a m e > e j b / G e r ~ e r i c A c c i ~ u r ~ t < / e j b - r e f - r t a r n e > . < e jb - r e f - t y p e > E r ~ t i t y < / e bj - ~ ~ e f - t y p e > .'home>wrox. s i > m e - i s v . A c c ~ i l ~ r ~ t H n m e / / h o m e > < r e r n , i t e > w r o x .some i s v . A c c o u r , t i / r e m o t e >

<ejb-linl:>Account</ejb-lir~k>
</ejb-ref> (security-role-ref> <description> )u t o m a t e d c u s t c ) m e r w i t h d r a w a l s T t ~ i sr o l e refel-s t ~ a from t h e a c c o u n t ; r l bank i n t e r m e d i a r y i s i r ~ v o l v e d . </descl-iption> <role-r~ame>ATl4i/rc31e-r~an1e>

La referencia de rol se vincula ahora a un rol determinado definido en este descriptor:

<entity\ <display-nameiAccour~ti/~iisplay-r~,ame> < e jb-name?Acc,,ur~~t</e b-name.> j ih<:jme>wrox.sorne-i s v . A c c o u n t H a m e < / h o m e > < l - e m o t e > w r o x .some - i s v . A c c o u n t C / r e m n t e ~ b-classi < e j b - c l a s s ' w r o x . some - i s v . A c c o u n t E ~ J B i / e j ~<persistence-type>Cor~tair1e~~</persister!ce-type> i p r i m - k e y - c l a s s i j a v a . l a r ~ gI. r ~ t e g e r < / p r i m - k e y - c l a s s : /reer~trar~t>Falsei/reer~trar~t>

Capitulo 18
</cmp-field, <cmp-field, <field-r~ame\accour~tBalar~ce fi < e/l d - n a m e > </cmp-field> <cmp-field> <f i e l d - r ~ a m e > a c c o u n t I O i / f i e l d - r ~ a m e > </crnp-field> <primkey-field>accour~tID</prin~key-field> <er~v-entry>

<er~v-er~try-r~ame>er~v/mir~im~rnBalar~ce~./er~v-er~try-r~ame>
C e n v - e n t r y - t y p e > j a v a . larjg. U o u b l e < / e r ~ v - e n t r y - t y p e > < e n v - e n t r y - v a l u e > l 5 0 . O</erlvVerltry-value, </env-erltry> </entity>

La porcion de descriptor de ensamblaje del descriptor de implementacidn puede ser omitida en el caso altamente improbable de que nuestra aplicacibn no requiera ningGn rol de seguridad, permiso de mCtodo o atributo de transaccidn:

Declaramos que todos 10s mitodos, en ambas clases, requieren un context0 de transacci6n nuevo o existente:

Definimos 10s roles de seguridad:


<security-role> <description> T h i s r o l e i s p e r f o r m e d by a n y c u s t o m e r - s e r v i c e r e p r e s e n t a t i v e who d o e s n o t h a v e a c c o u n t - m a n a g e r s t a t u s . They w l l l b e a b l e t o h a n d l e d e p o s i t s and w i t h d r a w a l s , b u t not a c c ~ u r ~ m ta n a g e m e n t . </description:>

<role-name>Teller</role-name>
</security-role? <security-role> <description> T h i s r o l e i s p e r f o r m e d by a n y a c c o u n t a c c e s s i n which a bank employee i s n o t i n v o l v e d , s u c h a s an internet transaction or A T M withdrawal . < / d e s c r i p t i o n > <role-r~ame>Ur~mediatedAccess</role-riame> </security-role\

Roles de desarrollo y de implernentacion


<security-role> <description> T h i s r o l e i s p e r f o r m e d by p r o f e s s i o n a l s who a r e a l l o w e d t o manage an a c c o u n t ( o p e n , c l o s e ) . < / d e s c r i p t i o n > <role-name>Manager</role-r~ame> </security-role>

Definimos 10s metodos a 10s que tiene acceso el rolManager (a todos ellos):

Definimos 10s metodos a 10s que tiene acceso el rol U n m e d i a t e d A c c e s s :

Capitulo 18

Definimos 10s mktodos a 10s que tiene acceso el rol T e l l e r :

Finalmente, definimos 10s mktodos a 10s que cualquiera tiene acceso:

Roles de desarrollo y de implernentacion

Capitulo 18
</method-params> </method> <method> <ej b - r ~ a m e > A c c o u n t M a r ~ a g e r < /b-riame> ej <method-intf>Remote</method-intf? <method-name>getEJBHome</method-name> <method-params / > </method> <method> <ej b-name>Account</ej b-r~ame> <method-intf>Home</method-intf>
<method-name>rernove</method-name>

<method-params> <method-param?j ava. 1ang.Obj ect</method-param> </method-params> </method> <method> j b-name> <ej b-riame>Accour~t</e <method-intf >Horne</method-intf> <method-narne>f i r ~ d B y P r i m a r y K e y < / m e t h o d - n a m e > <method-params> <method-param>j ava. lang. Ir~teger</method-param> </method-params> </method> <method> <ej b-name>Account</ej b-name>
<method-intf>Remote</method-ir~tf>

<method-name>getHandle</method-name> <method-params / > </met hod? <met hod? <ej b-name>Account</ej b-name>
<method-intf>Home</method-ir~tf>

<method-name>create</method-name> <method-params> <method-param>int</method-param> <method-param>java.lanq.String</method-param> <method-param>java.lang.String</method-param> <method-param>double</method-param> </method-params? </method> <met hod> b-rlarne> <ej b-name>Accour~t</ej <method-intf>Home</method-intf>
<method-name>remove</method-name>

<method-params> <method-param>javax.ejb.Har~dle</method-param? </method-params? </method> <method> <ej b-name?Account</ej b-name> <method-ir~tf?Home</method-intf>


<method-r~ame?qetHomeHar1d1e</method-r1ame>

<method-params / ? </method> <method> <ej b - r i a m e > A c c o u n t < / e j h - n a m e ? <method-intf>Remote</method-intf? <method-name>get P r i m a r y t i e y < / m e t h o d - r e > <method-params / > </method> <met hod>

Roles de desarrollo y de implernentacion

Como ensambladores de la aplicaci6n, hemos afiadido todo lo que depende del elemento < a s s e m b l y d e s c r i p t o r > . Para las transacciones gestionadas por contenedor, hemos especificado que todos 10s mktodos deben ejecutarse en una context0 transaccional. Para cualquier llamada de metodo de empresa, si no hay ninguna transacci6n actual, el contenedor creari una. Por rnotivos de seguridad, hemos definido tres roles: U n m e d i a t e d A c c e s s , T e l l e r y M a n a g e r . M a n a g e r tiene acceso a todos 10s mktodos; t e l l e r y " u n m e d i a t e d a c c e s s " (es decir, la Web o un cajero) s61o pueden depositar o retirar fondos. Ademis, hemos ahadido dos cosas el e l e m e n t o < e n t e r p r i s e - b e a n s > :
0

U n elemento < r o l e - l i n k > para la referencia del rol de seguridad en el bean de sesion. Recuerde que el c6digo (quizis obtenido de un vendedor de software independiente) hacia referencia a un rol de seguridad de ATM. Nuestra aplicaci6n quiere ser mis general y, por ello, utilizamos el rol U n m e d i a t e d A c c e s s . La indirecci6n de una referencia nos permite hacer esto: el elemento < r o l e - l i n k > cierra el ciclo. Una resolucion similar de una referencia, en este caso a otro bean. En nuestro c6dig0, el bean A c c o u n t M a n a g e r hace referencia a1 bean de la cuenta comoe j b / G e n e r i c A c c o u n t . Sin embargo, el verdadero nombre del bean es simplemente A c c o u n t . Los dos estin vinculados por el elemento<e j b - l i n k > .

Ahora hemos vinculado nuestros EJB para que formen una h i c a unidad de aplicaci6n desplegable. Nuestro deber como ensambladores de aplicaci6n termina aqui. Aunque todavia necesitamos implementar 10s clientes que, obviamente, no son parte de la unidad de aplicaci6n. Proporcionamos tres clientes: el primer0 sera ejecutado con la identidad de seguridad de un gestor y creari una par de cuentas y realizari un dep6sito y despuCs una extracci6n:
package import import

wrox. sume

Is v ;

j a v a . rmi .R e m o t e E x c e p t i c c r ~ ; j avax. e j b . +;

Capitulo 18
import import public j a v a x . rlaming.' ;

javax.rmi.Portab1eRemoteObject;
class Testclient void
(
(

public try
{

static

main(String[] args1

IrlitialContext Object obj ref

i n i t i a l = rlew I n i t i a l C o n t e x t ( ) ; i n i t i a l . loo!-:up ( " ja v a : c o m p / e n v / e j b / A c c o u r ~ t A c c e s s " ; )

AccountManagerHome home = ( o b jr e f , ( A c c o u r ~ t M a r ~ a g e r H o m eF ) ortableRemoteOb] e c t . r 1 a r r . i ~ AccountManagerHome. c l a s s ) ; AccountManager accour~tManager


=

home. c r e a t e ( 1 ;

System. o u t . p r i n t l n ( " c r e a t e i n d i v i d u a l account" ) ; a c c o u n t M a n a g e r . c r e a t e A c c o u n t ( 1 , "Dan O C o n n o r " , C u s t o m e r T y p e s . INDIVIDUAL,

1 5 0 0 . 0 );

Systern.uut . p r i n t l n ("withdraw"); accour~tMar~ager.withdra (w 1, 7 5 . 0 ."rate accr,untl') ; "Wrox P r e s s " ,

CustomerTypes.CORPORATION,
]

150000.0);

catch (Exception e ) [ e.printStackTrace ( 1 ;

El segundo cliente sera ejecutado con la identidad de seguridad de un cajero automitico o de un cliente Web. N o tendri Cxito en su intento de crear una cuenta, porque el contenedor EJB evitad el acceso a1 metodo basado en nuestros permisos de seguridad declarativa en el descriptor de implementaci6n. El siguiente c6digo busca n u e s t r o A c c o u n t M a n a g e r e intenta crear una cuenta. Puesto que las credenciales de seguridad de este cliente son insuficientes para este tip0 de operacibn, la solicitud fallara:
package import import import import w r t ~ ~s x o.m e l s v ; j a v a . rmi .R e m o t e E x c e p t i o n ; javax. ejb.*; j a v a x . naming. *;

javax.rmi.PortableRemote0bject;

rlublic c l a s s T e s t c l i e n t 2 { p u b l i c s t a t i c void main(Strir1g[ I a r g s ) { r \ i I r ~ i t i a l C o n t e x t i n i t i a l = r~ew I n i t l a l C o r t t e z t ( ) ; O b j e c t o b j r e f = i n i t i a l . lookup ( " j a v a : comp/eriv/ej b/Accour~tAccess" ) ; AccountManagerHorue home = ( o b jr e f , (Accour~tManagerHorne) PortableRemoteObj e c t . r ~ a r r o w

Accour~tManagerHome.class);
AccouritMariager accountManager
=

home. c r e a t e

) ;

Roles de desarrollo y de implementaci6n


System.out . p r i n t l n ( " c r e a t e " ) ; a c c o u n t M a r ~ a g e rc . r e a t e A c c o u r ~( t3,

"John Smith", C u s t o m e r T y p e s . INDIVIDUAL,

500.0) ;

1 catch (Exception e )
e.printStackTrace();

El tercer cliente sera ejecutado con la identidad de seguridad de un cajero automitico o un cliente Web. Conseguiri extraer una pequefia cantidad de dinero de la cuenta individual y una gran cantidad de dinero de la cuenta corporativa. Sin embargo, debido a la comprobaci6n de seguridad que hemos escrito, el intento de retirar una gran cantidad de dinero de una cuenta individual fallari:
package import import import import wrox.some isv;

j ava rmi R e m o t e E x c e p t i o r ~ ; j a v a x . e j b . *; j a v a x . n a m i r ~ g *; .

javax.rmi.PortableRemote0bject;

public class TestClient3 { public s t a t i c void main(String[] a r g s ) { try I I n i t i a l C o n t e x t i n i t i a l = new I n i t i a l C o n t e x t ( ) ; O b j e c t o b j r e f = i n i t i a l . l o o k u p ( " j a v a : c o m p / e r ~ v / e j b / A ~ ~ ~ ~ r ~ t A c; cess") AccountManagerHome home = ~ A c c o u n t M a n a g e r H o m e ~P o r t a b l e R e m o t e O b j e c t . n a r r o w ( o b j r e f , AccountManagerHome. c l a s s ) ; AccountManager accountManager
=

home. c r e a t e ( ) ;

System.out p r i n t l n ( " w i t h d r a w i n g s m a l l amount accountMar~ager.withdraw(1, 1 0 0 . 0 ) ;

from

individual

account") ;

S y s t e m . o u t . p r i n t l n ( " w i t h d r a w i r i g l a r g e amount accountMar1ager.~ithdraw(2,1 0 0 0 . 0 ) ; System.out . p r i n t l n ( " w i t h d r a w i n g l a r g e amount a c c o u n t M a n a g e r . w i t h d r a w ( 1, 1 0 0 0 . 0 ) ;

from c o r p o r a t e

account") ;

from

individual

account") ;

catch (Exception e ) { e.printStackTrace ( ) ;

Recuerde que n o existe un procedimiento estindar para la autentificacidn del cliente en la especificaci6n Enterprise JavaBeans. Sin embargo, asi como un cliente aut6nom0, la especificaci6n JZEE provee el concept0 de un cliente ejecutado en un contenedor. Este contenedor proporciona servicios de nivel de sistema, igual que un EJB o un servlet que se ejecuta en un contenedor que ofrece servicios de nivel de sistema.

Capitulo 18
Aunque las tkcnicas de autentificacidn no son especificadas por el contenedor cliente, es obligatorio algtin tipo de autentificacidn. La interfaz remota proporciona automa'ticamente esta autentif;:cacidn para clientes ejecutados en su "contenedor cliente". ( U n contenedor cliente es sdlo una aphacidn esta'ndar que "envuelve" su aplicacidn. La invocamos, pasando el nombre de nuestra aplicacidn como para'metro e invocara' nuestro mitodo de aplicacidn ma i n () .) Aunque no hay c6digo de autentificaci6n en estos tres ejernplos, a1 ser ejecutados, apareceri una ventana que solicite un nornbre de usuario y una contraseiia:

Al final de la fase de ensarnblaje de la aplicaci6n, tendrernos una aplicaci6n cornpleta preparada para su irnplernentaci6n en un servidor de aplicaci6n. Corno con otros ejernplos, debernos ernpaquetar nuestros cornponentes EJB en un archivo JAR. Cornpilernos estas clases ejecutando el siguiente cornando:
javac

-d

-classpath

. ; % J 2 E E P H O M E % \ l i b \ j 2 e e .j a r

src\wrox\some-isv\*.

j ava

Ahora debernos tener 10s siguientes archivos y directorios:


I

sv\
META-INF\ w r o \ some-isv\ Account.class AccountEJB.class AccountHome. c l a s s AccountManager. c l a s s AccountManagerEJB. c l a s s

AccountManagerHome.class
CustomerTypes.class I n s u f f i c i e n t F u n d s E x c e p t i o r ~c .lass NoAccour~tCreatedExceptior~ c .l a s s NoSuchAccour~tExceptior~ c. lass Testclient. class TestClient2. class

Podernos crear el archivo JAR ejecutando el siguiente cornando:


j ar

cvf

account. j a r

META-INF/

wrox/si?me-isv/

N o es necesario que las clases Tes t c l i e n t e s t b en nuestro archivo JAR; sin embargo, sera' necesario que nuestro archivo J A R estk en nuestra ruta de clase cuando ejecutemos 10s clientes.

Roles de desarrollo y de implernentacion

El implementador
Una vet se ha completado la aplicacion, debe ser insertada en el entorno de destino. Recuerde que el programador de 16gica de empresa no tiene que preocuparse por la base de datos de destino, el sistema de seguridad, c6mo encontrar otros componentes referenciados o c6mo encontrarin 10s clientes el EJB. Pero estos temas tienen que ser considerados eventualmente y las referencias logicas que utiliza el proveedor de bean deben ser asociadas a recursos o identidades reales. Este proceso es especifico del vendedor de servidor de la aplicacidn y la responsabilidad de llevarlo a cab0 recae en el implementador. N o es necesario que sea un experto de campo (es decir, un experto en la empresa); una persona en este rol debe ser en cambio un experto en el entorno en el que se ejecutari.la aplicacion (es decir, un experto en la base de datos de la compafiia, en el sistema de seguridad, en el servidor de aplicacion, en 10s sistemas operativos y en la red). Consideremos qu6 necesitamos hacer para implementar nuestra aplicacion en el servidor de aplicacion de referencia J2EE. Para implementar la aplicacion en nuestro entorno configurado, utilizaremos la herramienta de interfaz remota, deploytool. Una vez iniciada la herramienta de implementaci6n, Cree una nueva aplicaci6n llamada wrox, seleccione entonces File (Archivo) I Add to Application (Atiadir a la aplicacion I EJB JAR ...:

d META-INF d src dwrox


accoun

Seleccione nuestro archivo account. j ar y haga clic en Add EJB JAR (Agregar EJB JAR). Podemos ver ge y Account: que hemos afiadido efectivamente dos EJB a nuestra a p l i c a c i 6 n , ~ c c o u n t ~ a n a r

Capitulo 18

Rpplic &on Dtsptw Name I

I Wrox

account.lar META-INFIMANIFEST.MF METAlNFlapplicalionxml METkINFlsunj2ekri.xmI

A continuaci6n, es necesario que asociemos 10s roles de seguridad 16gica, que hemos definido a1 ensamblar la aplicaci6n, a usuarios y grupos reales del sistema de seguridad subyacente. Utilizaremos un sencillo sistema de seguridad que viene integrado a1 servidor de aplicaci6n de referencia como demostraci6n. Observe que, aunque este sistema de seguridad estl incluido en la Implementaci6n de Referencia, n o forma parte en absoluto de la plataforma JZEE. El h i c o requisito que se aplica a un servidor J2EE o a un contenedor EJB es que se asocian a algGn sistema de seguridad; la Implementaci6n de Referencia incluye este sencillo sistema de seguridad para cumplir este requisito. (En realidad, hay dos sistemas de seguridad que vienen integrado en la plataforma J2EE; junto con el sencillo sistema de seguridad que utilizaremos, el otro es un sistema basado en un certificado para clientes navegador que utilizan el protocolo H'ITPS.)
Seleccione el apartado Security (Seguridad)para nuestra aplicaci6n. Esta secci6n se utiliza para asociar roles 16gicos (como U n m e d i a t e d A c c e s s , M a n a g e r y T e l l e r ) a usuarios y grupos reales del sistema de seguridad (como WebGroup y A T M G K O U ~ ) :

Roles de desarrollo y de implernentacion

Role Names Referencerl:


Role Name

Users in Role:

UJerName

Seglin la especificacibn EJB, aiiadir usuarios y grupos a1 entorno operativo es una tarea del adrninistrador del sisterna. Sin embargo, para permitir a1 implernentador seleccionar de una lista, adoptarernos las funciones del adrninistrador del sistema y verernos cbrno son aiiadidos utilizando la interfaz rernota. El servidor JZEE nos perrnite ariadir y extraer usuarios y grupos utilizando una herramienta de linea de comando r e a l m t o o l . Aiiadiremos cuatro grupos: T e l l e r G r o u p , ATMGroup, ManageGroup y WebGroup. Cada grupo tiene un u s u a r , i o : ~ a m p l e ~ e l l eSampleATMUser, r, SampleManagery SampleWebUser, respectivarnente. Estos son 10s grupos de seguridad "reales" que asociamos a 10s roles abstractos en la aplicacion bancaria. Para crear 10s grupos y usuarios requeridos ejecutamos el siguiente comando, utilizando la utilidad r e a l m t o o l localizada en el directorio% ~2 EE-HOME% \ b i n :
realmt43ol realmtool realmtool realmtool realmt13ol realmtool realmtool realmtool -addGroug T e l l e r G r o u p - a d d C r n u p ATMGroup - a d d G r o u p ManagerGrcrup - a d d G r o u p WebGroup -add S a m p l e T e l l e r p a s s w a r d l T e l l e r F r o u p - a d d SampleATMUser p a s s w o r d 2 ATMGroup -add SarnpleManager p a s s w o r d 3 ManaqerGroup - a d d SampleWe$User p a s s w o r d 4 WebGroup

Reinicie el servidor JZEE de rnodo que estos cambios pueden surtir efecto. Ahora podemos volver a adoptar el papel de desplegador y conectar la herrarnienta de despliegue al servidor JZEE y volver al apartado Security de nuestra aplicacibn. Para asociar un usuario o un grupo a un rol, podemos simplemente seleccionarlo de las opciones disponibles utilizando el bot6n Add ....( Agregar). Para asociar un usuario o grupo real a un rol16gico en la implementaci6n de referencia JZEE, seleccionarnos el rol y despues hacemos clic en el bot6nAdd:

Capitulo 18

Users:

User ~roups:

Podemos ahora seleccionar 10s nombres de usuarios y grupos que acabamos de crear con la herramienta realmtool. A f i a d a ~ a m p l e ~ ~ ~ ~ a se mr p, le~eb~ser,~eb~roupy~~~~roupa~rol ~nmediated~ccess;~ample~anagery~anager~roupa~ro~~anager,ySampleTellery ~eller~rou a1p rol~eller:

Roles d e desarrollo y d e implementaci6n

Edn 1 -

rn
- ---

9 d Flles
9

I ~~i~lS16qq [BB]p!$zq RBI ~ F C q ~ -Ir~spect~og Flles.Applica(~ons.Wox Cj~ppllcat~ons Q wrox B @ lSVs a3 AccounlManager @Account @ sewers localhost

loriLn1-(-s%wrvI
m l e Names Referencnl: Role Name UnmeUlatedAccessManager Users m Role: User Nal

Ahora necesitamos asociar nuestro acceso a base de datos 16gica a una base de datos real. S d o hemos configurado una base de datos en nuestro entorno, la base de datos por defecto Cloudscape que viene incorporada a la interfaz remota J2EE y que estl asociada a1 nombre J N D I j d b c / C l o u d s c a p e . Ademis, necesitaremos asociar las propiedades de la persistencia gestionada por contenedor de nuestro bean de e n t i d a d ~ c c o u n a t campos reales de la base de datos. Aceptaremos una asociaci6n por defecto y permitiremos a1 servidor de la aplicaci6n crear nuestra tabla de base de datos a1 implelnentar nuestro bean. (Aunque esto probablemente no serfa posible en un entorno de producci6n, resulta muy conveniente a la hora de experimenta con la plataforma.) Seleccione el bean A c c o u n t , despuks el apartado Entity (Entidad) y, finalmente, Deployment Settings (Parametros de implernentacion). Esta pantalla nos permite asociar nuestro estado de entidad a una determinada base de datos asociada al espacio de nombre global JNDI; asi como asociaciones a una determinada tabla o columna. Haga clic en Database Settings (Parametros de bases de datos), introduzca j d b c / C l o u d s c a p e en Database JNDI Name (Nombre JDNl de base de datos) y pulseOK (Aceptar):

-Database Settings Database JNDI Name:

--

I jdbclCloudscape
User Name:

Capitulo 18
Marque Container Methods (Mktodos de contenedor) y pulse Generate Default SQL (Generar SQL):

8 3 Remote FimBerm

C !Select Hethods
r D Container Methods

U n servidor de aplicaci6n comercial (o un servidor de fuente abierta) proporcionaria normalmente capacidades de asociaci6n objeto/relacional m i s sofisticadas. Las limitaciones actuales del servidor de referencia en este aspect0 son bastante estrictas. La siguiente informaci6n esti tomada de las notas de lanzamiento de Sun:
O

La clase bean d e entidad s61o puede asociarse a una tabla en la base de datos. Cuando el contenedor carga 10s campos gestionados por contenedor desde la base de datos subyacente, carga todos 10s campos. Si hay una gran cantidad de datos, este enfoque puede resultar poco eficiente debido a que el mktodo de empresa quizis n o necesite todos 10s campos gestionados por contenedor. Si el campo de mliltiples beans de entidad gestionado por contenedor se asocia a1 mismo elemento de datos en una base d e datos y, si estos beans son invocados en la misma transacci611, quizis se obtenga una vista inconsistente del elemento de datos. La herramienta de despliegue genera instrucciones S Q L para 10s mktodos e jbcreate ( ) , e j bRemove ( ) , e jbLoad ( ) y e j bStore ( ) . Podemos modificar s61o 10s nombres de la tabla y la columna de estas instrucciones SQL. N o podemos modificar el nlimero ni el orden de 10s signos de interrogacibn, que son 10s soportes de espacio para 10s parlmetros de entrada. N o podemos invocar procedimientos almacenados en las instrucciones S Q L generadas. En la instrucci6n S Q L CREATE TABLE, podemos cambiar el tipo S Q L de una c o h m n a de la tabla, siempre que el tip0 S Q L sea compatible con su correspondiente variable d e instancia. Los nombres de la tabla y de la columna en todas las instrucciones S Q L deben ser consistentes. Las instrucciones S Q L generadas han sido probadas con Cloudscape, Oracle y Microsoft S Q L Server. Quizis necesite editar las instrucciones S Q L para satisfacer 10s requisitos de otras bases de datos.

o U n campo gestionado por contenedor puede asociarse s61o a una columna de la tabla.
L I

L I

0 0 0 0

Roles de desarrollo y de imglementacion


Finalmente, necesitamos asociar todos 10s beans y referencias en el espacio de nornbres JNDI. Observe que la herramienta de implementaci6n respetari cualquier vinculo entre 10s beans declarados por el ensarnblador de la aplicaci6n utilizando el elemento < e j b- l i n k > . . En este ejernplo, el b e a n ~ c c o u n t ~ a n a g esti e r asociado a1 espacio de nornbres global bajo el nombre A c c o u n t M a n a g e r . El b e a n ~ c c o u n estl t asociado a1 espacio de nornbres global bajo el nombre A c c o u n t . Es conveniente utilizar el rnisrno nornbre para el bean y el espacio de nombres, per0 no es un requisito indispensable. U n cliente que no esti siendo ejecutado en un "contenedor cliente" utilizari este nornbre J N D I para encontrar el bean desde contexto inicial JNDI. La referencia e j b / G e n e r i c A c c o u n t que utiliza el b e a n ~ c c o u n t ~ a n a g es e rautorniticarnente asociada a Account, porque t e j b - l i n k > les obliga a ser la misrna. Los tres clientes que hernos definido corno clientes de aplicaci6n JZEE (que ejecutarernos en un contenedor cliente) utilizan el rnisrno tipo de vinculo que utilizaria una referencia EJB. En su c6dig0, buscan e j b / A c c o u n t A c c e s s desde el contexto inicial, que esti asociado aquial bean AccountManager:

..

ComponentTpe EJ9

Component Accountklanaeer Account

[-

JNDl Name

1
,

Acco~n1bnana~er 'Account

, References
Resource

. -

... .

Referenced lWs[CMPl
Jdbc{Clo~~SCape

,
1

La especificaci6n Enterprise JavaBeans requiere que el servidor proporcione herrarnientas para realizar esta asociaci6n. N o es necesario que tengan un GUI; pueden ser archivos XML editados rnanualrnente. Ahora podemos afiadir 10s clientes de prueba a nuestra aplicaci6n. En cada cliente, seleccione File (Archive) ( New (Nuevo) I Application Client (Cliente aplicacion) y afiada la clase relevante a la aplicaci6n:

Capitulo 18

Please select the appllcation that this application client is targeted to and a JAR file will be added to it. Add the class flles for this application client to M e contents ofthe JAR file.

Create Archive Wilhin A(~plicatiolr

Pulse Next (Siguiente) hasta llegar a la pantalla Enterprise Beans References. Pulse Add e introduzca e j b/ AccountAccess corno valorparaC~ded Name, wrox .some+isv .AccountManagerHome parala interfazHome Interface ywrox. some isv .AccountManager paraLocal/Remote Interface. Seleccione entonces JNDl Name e i n t r o d u z c a ~ c c & . m t ~ a n a ~ como e r valor:
Please list am/ Enterprise Beans that are referenced In Ihe code of lnls appllcalon cllenl For each ofthese. p m d e thetwe ol bean required (session or enlily), and the ciars names Qncludlnppackage) ofthe Home and Remote Interfaces eapected. &SO, please prOWd0 a destrip%on of me 6aQeclad behavior oreach bean referenced.

EJWS Retwanced la Code

Haga clic en Finish (Finalizar) y repita lo mismo para 10s tres clientes. Cuando hayarnos terrninado, nuestra pantalla principal quedari asi:

Roles de desarrollo y de implernentacion

Component Acc\SEourj+eger_ b e t

JMDIName A c ~ u n ~ ~ a g e r' Account _ '

11

8 Accounmanager

6 sewers B localhost

Ref TWe
EJB Ref ~EJB Ref EJB Ref

Referenced --& AcrountManagef TeslCllent ~estcl~enfit TestCllenQ

Reference NemeJ JNDI Name e~blOenerlcAcCount A r f o y l e)b(AccauntAccess Accounhlana~er eJWAEcountAccess Pctodntusnager-

1'

Hemos configurado la aplicaci6n. A continuacih, la implementaremos y ejecutaremos 10s clientes. Asegcrese de que el servidor J2EE esti siendo ejecutado y seleccione Tools (Herramientas) I Deploy (Implementar),acepte ]as configuraciones por defect0 e implemente la aplicacidn Wrox en el servidor. Para ejecutar 10s clientes necesitamos configurar la variable de entorno APPCPATH para referenciar account. j a r y despuks ejecutar 10s siguientes comandos desde el directorio en el que hemos almacenado~rox .ear:
runclient runclient runclient -client -client -client

Wrox.ear -name Wrox. ear -name Nrox.ear -name

Testclient TestClientZ Testclient3

Se nos solicita un nombre de usuario y una contraseiia (si se utiliza el indicador -textauth con runclient, podemos introducir la informaci6n de registro en el comando invitaci6n):

P a r a ~ e s t c l i e n podemos t utilizar el nombre d e usuario de S a m p l e M a n a g e r y la contraseiia d e p a s s w o r d 3 que hemos configurado con r e a l r n t 001:

I n t e n t e utilizar S a m p l e A T M U s e r c o n T e s t C l i e n t 2 y v e r i q u e el cliente n o s e ejecuta correctamente porque el usuario n o tiene 10s permisos de seguridad pertinentes. Intente ejecutarlo d e nuevo, pero esta vez c o m o S a m p l e M a n a g e r :

Intente ejecutar T e s t C l i e n t 3 con10 S a m p l e A T M U s e r y veri que, aunque puede conseguir extraer una pequena cnntidad d e dinero, la aplicacicjn n o permitir5 la extracci6n d e una cantidad m u y superior. D e nuevo, s i ~ e s t ~ l i e nes t3 ejecutado c o m o S a m p l e M a n a g e r , la ejecucicjn se renliza con ixito:

Roles de desarrollo y de implernentacion

El adrninistrador del sistema es responsable de configurar el senidor de aplicaci6n, el contenedor EJB y el entorno en el que se ejecutan, incluido base de datos, red y sistemas de seguridad. El administrador del sistema tambikn es responsable de garantizar una ejecuci6n optima del EJB dependiendo de 10s recursos provistos por el entorno, incluido mernoria y ancho de banda de la red. El administrador del sistema configura el entorno del senidor de aplicaci6n. La interfaz remota, (aunque no pretende ser un sistema comercial) proporcionar un cierto margen de configuraci6n. En concreto, 10s siguientes elementos pueden ser configurados de forma manual editando archivos de configuraci6n que residen en el d i r e c t o r i ~ c o n f(estin i~ documentados en % J 2 E E-HOME% \ d o c \ r e l e a s e \ ~ o n i fg ~ u i d . eh t m l ) :

Controladores JDBC

0 Transacciones

U Nurneros de puerto

u
O

Ficheros de registro Seguridad Umbrales de rnemoria para pasivacion Raiz de documento H T T P

El controlador JDBC que elijamos dependera de la base de datos que utilicemos. Para algunas bases de datos, estari disponible rnis de un controlador JDBC. Tarnbiin podemos configurar el I D y contraseiia o s conexion en de usuario para conexiones a bases de datos (a rnenos que obtengarnos y a ~ t e n t i f i ~ u e r n una codigo). Se aiiade un controlador JDBC configurando el archivo de propiedad d e f a u l t . p r o p e r t i e s y aiiadiendo el controlador a !a ruta de clase del servidor. Las transacciones distribuidas pueden ser configuradas para recuperation o para la no-recuperation, en caso de un fallo del servidor. Para 10s EJB con transacciones gestionadas por contenedor, el period0 para plazos limite de transaccion puede configurarse e n d e f a u l t .p r o p e r t i e s . La Irnplernentacion de Referencia J2EE utiliza cuatro puertos TCP/IP:
O L I

El servicio EJB utiliza uno para descargar clases de stub para el cliente El senicio H T l T utiliza uno para solicitudes de servicio El senicio HTTPS utiliza otro para solicitudes de servicio

Finalmente, Object Request Broker (ORB) subyacente a1 servidor de nombre J N D I utiliza un puerto

Los numeros de puerto utilizados para descargar clases de stub EJB pueden ser configurados en e j b . p r o p e r t i e s . Los otros puertos pueden confiprarse en Web. p r o p e r t i e s . El senidor J2EE tambikn produce varios ficheros de registro y podernos cambiar el directorio predeterminado o el nornbre de estos archivos e n d e f a u l t . p r o p e r t i e s . Podemos configurar varias opciones de seguridad. La contraseiia k e y s t o r e preterminada es " c h a n g e i t ". Podemos cambiarla editando las entradas k e y s t o r e . p a s s w o r d en el archivo Web. p r o p e r t i e s . Cuando un cliente Web autentificado realiza una llamada sobre un EJB, obtiene un principal de un usuario genkrico. Podemos modificar el nornbre del usuario no autentificado editando a u t h . p r o p e r t i e s . En la herramienta de implernentacion de la edition de referencia, se asigna a 10s

Capitulo 18
metodos un rol por defecto llamado ANYONE, que representa el conjunto de todos 10s usuarios y grupos. Podemos cambiar el nombre de este rol predeterminado a u t h . p r o p e r t i e s . Ya hemos hablado sobre pasivaci6n. Por defecto, el servidor pasivari beans de sesi6n cuando el uso de memoria supere 10s 128 megabytes. Podemos cambiar este umbra1 en d e f a u l t . p r o p e r t i e s . La especificacion J2EE incluye servlets y paginas JSP, y la implementaci6n de referencia contiene un sewidor Web con un documento por defecto raiz d e p u b l i c - h t m l ; podemos cambiarlo en
Web . p r o p e r t i e s .

Estas configuraciones son especificas de la implementaci6n de referencia J2EE y otros sewidores de aplicacion tendrin un conjunto diferente de ~onfi~uraciones. Esta configuraci6n puede realizarse en un fichero de propiedad, igual que la implementaci6n de referencia o utilizando una herramienta GUI. A pesar de todo, siempre seri necesario que configure el sewidor de aplicacion elegido para que se ajuste a1 entorno concreto. El administrador del sistema t a m b i h debe controlar el entorno de aplicacion utilizando herramientas especificas de servidor de aplicaci6n. La linica herramienta establecida como obligatoria por la especificaci6n EJB es un registro en el que puede realizarse un registro de excepciones de sistema. Los registros son, de hecho, las 6nicas herramientas de control provistas por la implementaci6n de referencia. Existe una nueva especificaci6n Java para gesti6n de aplicaci6n y de red llamada Java Management Extensions UMX, http://java.sun.com/products/JavaManagernent/). Es un sistema exhaustivo que incluye control de propiedades, servicios dinimicos de gestibn, apoyo para varios protocolos de gesti6n como Simple Network Management Protocol (SNMP) y la capacidad de gestionarlos a travks de la Web. A1 menos uno de estos contenedores EJB de c6digo abierta, JBoss, esti siendo disehado completamente alrededor de JMX y es bastante probable que la mayoria de servidores de base Java se normalicen en el futuro tomando como referencia estas extensiones de " eesti6n. Esto ~ e r m i t i ra1 i desarrollador de ETB conseguir que su aplicaci6n sea gestionable de un mod0 estindar y portitil. Sin embargo, no eliminari las herramientas de gesti6n del campo de la cornpetencia entre vendedores de aplicacidn y esto seguiri siendo un irea en la que 10s vendedores pueden marcar diferencias.

Vendedor de contenedor/servidor de aplicacion


~ s t es e el liltimo rol definido por la especificaci6n EJB. Aunque este libro no esti dirigido a1 proveedor de un servidor de aplicaci6n, todavia necesitamos elegir un servidor de aplicaci6n/contenedor EJB y, como ese contenedor EJB seri responsable de todos nuestros servicios de nivel de sistema, esta elecci6n seri importante para el kxito de nuestro proyecto. En el mercado, hay mis de 35 productos que se ajustan a EJB, con diversas capacidades y precios y elegir entre ellos puede resultar bastante dificil. La mayoria de 10s vendedores proporcionarin una copia de evaluaci6n de su servidor de aplicaci6n para un cierto periodo de tiernpo. Podemos desarrollar un producto en una implementaci6n gratis o de bajo precio y desplegarlo entonces en un producto comercial que cubra las necesidades de periodo de ejecuci6n. La implernentaci6n de referencia, 10s tres proyectos J2EE de fuente abierta, el sewidor de aplicaci6n Orion (que es de desarrollo gratis) son todas opciones posibles para un desarrollo de bajo coste. Por supuesto, si ya conoce su servidor de aplicaci6n de destino, quizis quiera desarrollarlo en esta plataforma para obtener experiencia con 61 y advertir aquellos elementos que pueden no funcionar. N o existe sustituto para la evaluaci6n de un producto en su entorno per0 esto puede llevarse demasiado lejos. N o es probable que merezca la pena invertir el tiempo y el dinero necesario para evaluar una docena de productos diferentes que se ajustan a EJB en un estudio para encontrar el perfecto para una situaci6n cbncreta.

Roles de desarrollo v de im~lementacion


Debemos comprender cuiles son nuestros requisitos antes de tomar una decisidn y 10s siguientes criterios probablemente sean consideraciones a tener en cuenta: iNecesitamos un producto de base ORB para comunicar con clientes no-Java o para interoperatividad de vendedor? iQuk capacidades de asociacidn objeto/relacional requerimos? iNecesitamos (y se ajusta a1 vendedor) asociar una entidad a multiples tablas? iCuiles son las caracteristicas de rendimiento la solucidn de un vendedor? Si no estamos satisfechos con las capacidades de asociacidn objeto/relacional de un vendedor, iexiste un producto tercero que se integre a1 sewidor de la aplicaci6n? iQuk tipo de herramientas de desarrollo e implementaci6n apoya un sewidor de aplicaci6n de un vendedor? Algunos productos proceden de un ambiente de proporcionar conjuntos de herramientas productivas. iCuiles son las caracteristicas de rendimiento de un determinado producto? iEs compatible con la clusterizaci6n para el rendimiento y la alta disponibilidad? iQuk versi6n de la especificaci6n Enterprise JavaBeans apoya el sewidor de la aplicaci6n? Algunos productos muy conocidos y populares, pueden quedarse atris. iSobre quk plataforma(s) se ejecuta el sewidor de la aplicacidn? i C u i n t o cuesta el producto que esti considerando? iQuk tip0 de apoyo esti disponible para el producto? En general, es mejor comenzar experimentado con EJB con un contenedor gratis. El problema de 10s sewidores gratis es que, aunque son buenos a la hora de proveer tecnologias, normalmente se quedan cortos en el momento de distribuir un verdadero producto (por ejemplo, ninguno de ellos apoya actualmente la operacidn de agrupamiento o clustering). Despuks de familiarizarse con 10s EJB, debe investigar 10s sewidores comerciales y probar (normalmente de forma gratuita) la versidn de evaluaci6n. Es tambikn importante obsewar el grado de avance del sewidor en cuanto a la versidn EJB; cualquier sewidor que ya ofrece un EJB 2.0 probablemente tengan una sdlida implementacidn 1.1.

El Capitulo 23 analiza con mds detenimiento 10s factores y 10s pardmetros a tener en cuenta a la hora de seleccionar un sentidor de aplicacio'n compatible con JZEE.

Una interfaz Web para la aplicacion


C o m o ejemplo de cdmo puede utilizarse 10s componentes EJB para crear una aplicacidn J2EE completa, vamos a proporcionar una interfaz Web para la aplicaci6n de fabricaci6n que ya hemos desarrollado en anteriores capitulos. (Como la mayoria de aplicaciones de prueba, s e r i ligera en el manejo de errores y funcionamiento sdlido, con el objetivo de mantenerla sencilla y clara.) La aplicacidn Web presentari un men6 de opciones para el usuario que le permitiri crear un producto de prueba, presentar un pedido de prueba, gestionar pedidos o fabricar un producto para un pedido. La pantalla de menu sera asi:

Capitulo 18

II

Choose one of the followmg actions:


Create a sample product Place a s m p l t order Idartage ordm Manufacture a product for an ordrr

Anteriormente, hemos analizado la arquitectura de controlador de vista de modelo y c6mo se aplica a aplicaciones Web. Recuerde el diagrama que representaba un posible diseiio de controlador de modelo de vista:

Vistas

Controlador

'

Nuestra aplicaci6n de factoria implementari este diseiio. El modelo serin nuestras fachadas EJB existentes (10s beans de sesi6nManageOrders y Manuf a c t u r e ) , mis una clase JavaBean l l a m a d a ~ o d e l ~ a n a ~ e r que actuari como un proxy para 10s EJB. El controlador seri una pigina JSP, llarnada m a i n . j s p , que enviad el procesarniento a un JavaBean llamado R e q u e s t p r o c e s s o r . R e q u e s t P r o c e s s o r actualizari el modelo y devolveri entonces la vista apropiada a m a i n . j s p . La pigina JSP m a i n . j s p enviari el procesamiento a la vista que ha devuelto R e q u e s t P r o c e s s o r , que seri tambiin un componente JSP. $te es un diagrama de la implernentaci6n:

Roles de desarrollo y de implementation

Manufacture

Controlador

createroutlng.jsp
...y otros

Chente
I Navegador

Examinemos el c6digo fuente para estas clases. (Algo que debemos sefialar es que n o estamos utilizando t a b l i b s en nuestras piginas JSP. Aunque son mis mantenibles que grandes cantidades de directivas, conllevan cierto trabajo importante que nos distraeria del tema principal de este capitulo.) Primero, m a i n . j s p , en el que el modelo y el procesador de solicitud estin en el alcance s e s s i o n :
< j s p : useBean id="rnodelManager" class="factory.ModelMar~ager" scope="session" > <% r n o d e l M a n a g e r . i n i t ( c o n f i g . g e t S e r v l e t C o r ~ t e x [t ,
%>

session);

</ j s p : useBean>
< js p : useBean i d = ' ' rp"

class="factory.RequestProcessor"
scope="session"

>
<%

rp. i n l t (config.getServletCor~text ( ),
%>

session);

</ j s p : useBean>

Enviamos la solicitud a la clase R e q u e s t p r o c e s s o r , que actualiza el modelo y devuelve la siguiente vista en la secuencia de aplicaci6n: <%
String targetview
=

rp.processRequest(request);

Capitulo 18
Ahora generamos la solicitud a la vista apropiada:
getServletConfig0.getServletContext~).

getRequestDispatcher(targetView).forward(request, r e s p o n s e ) ;
%>

~ s t es e el cddigo para laclase RequestProcessor. Para cada solicitud, actualiza el modelo y decide sobre la siguiente vista de secuencia:
package import import import import import import import import import import import factory;
j ava. t e x t . DateFormat; java.util.Date; javax. s e r v l e t . ServletCor~text;

javax.servlet.http.Htt.pServ1etRequest; javax.servlet.http.Htjavax.servlet.http.HttpServletRespnnse;tpServ1etRe~p~r~se; javax.servlet.http.HttpSessior1;


f a c t o r y . manage o r d e r s . N o S u c h O r d e r E x c e p t i o r ~ ; f a c t o r y . m a n a g e orders.NoSuchProductException; f a c t o r y . m a n a g e orders.Duplicate0rderException;

factory.manufacture.BadStatusExceptior~;
f a c t o r y . o r d e r .OrderNotCar1ce1ab1eExceptior1;

p u b l i c c l a s s Request.Processor [ p r i v a t e ModelManager mm; p r i v a t e UttpSession session; private ServletContext context; p r i v a t e S t r i n g stackURL; private DateFormat dateFormat = DateFormat. . g e t D a t e I r ~ s t a r ~ c ( DateFormat. e SHORT) ;

En el metodo init ( ) , obtenemos una copia del proxy modelo:


p u b l i c void i n i t (ServletCont.ext context, HttpSession s e s s i o n ) t h i s . session = session; this.context = context; mm = ( M o d e l M a r i a g e r )s e s s i o n . g e t A t t r i b u t e ( " m o d e l M a n a g e r " ) ;
{

I
El resto de la clase esti dedicada a1 procesamiento de la solicitud. Esto puede implicar obtener parimetros de la solicitud y actualizar el modelo consecuentemente o configurar atributos en la solicitud que podria examinar una vista posterior. El flujo de pantalla esti implicito en el codigo. Una aplicacidn mis completa necesitaria un mecanismo mis elegance; quizis un procesador de miquina de estado finito, con las transiciones de estado definidas en la base de datos. Aunque alga intimidatorio, el siguiente fragment0 de codigo es un sencillo lanzador de proceso: analiza el URL que esti siendo solicitado y devuelve un c6digo correspondiente a la acci6n que desea el usuario:
p u b l i c S t r i n g processRequest(HttpServ1etReyuest r e q ) S t r i n g selectedlJRL = req. g e t P a t h I n f n ( ) ; if
]
{

( ( s e l e c t e d U R L == n u l l ) I I s e l e c t e d U R L . e q u a l s ( ScreenNames. CHOICES) ) r e t u r n ScreenNames.CHOICES U R L ; e l s e i f (selectedLlRL.equa1~ (ScreenNames.CHOOSE FOR MANUFACTURE) ) S t r i r ~ g cellNarne = m m . q e t C u r r e n t C e l l ( ) ; i f ( c e l l N a m e == n u l l ) { / / requiere registro O R MANUFACTURE URL; stack!JRL = S c r e e n N a m e s . CHOOSE F r e t u r n S c r e e n N a m e s . CHOOSE C E L L URL;

Roles de desarrollo v de im~lementacion


return
]

ScreenNarnes.CH0OSE

FOR M A N U F A C T U R E U R L ;

e l s e i f (selectedURL.equals(Screer~Narnes.0RDER C H O S E N ) ) { try 1 String salesDiv = req.getPararneter(Screer~Narnes.SALESD I V I S I O N P A R A M ) ; S t r i n g o r d e r I D = req.getPararneter(Screer~Narnes.0RDERNUMBER P A R A M ) ; rnrn. s e l e c t F o r M a n u f a c t u r e ( I r ~ t e g e . rp a r s e I r ~ ( ts a l e s D i v ), 1nteger.parseInt (orderID)) ; i f (rnrn. h a s N e x t R o u t i n g ( ) ) I r e t u r n S c r e e n N a r n e s . R O U T E FOR MANUFACTURE U R L ; 1 else { r e t u r n S c r e e n N a r n e s . S H I P URL;

1
}

catch

(NoSuchOrderException

nsoe)

req.setAttribute(Screer~Narnes.MESSAGE ATTRIB, " T h e order does n o t e x i s t i n t h e s y s t e m . " ) ;


]

r e t u r n S c r e e n N a r n e s . M E S S A G E URL; c a t c h ( B a d S t a t u s E x c e p t i o n bse) {

req.setAttribute(Screer~Narnes.MESSAGEA T T R I B ,
" T h e order is n o t e l i g i b l e f o r m a n u f a c t u r e . " ) ; r e t u r n S c r e e n N a r n e s . M E S S A G E URL;

1
)

e l s e i f (selectedURL.equals(Screer~Narnes.CREATEP R O D U C T ) ) r e t u r n S c r e e n N a r n e s . C R E A T E PRODUCT U R L ;

1 else i f

(selectedURL.equals(Screer~Narnes.CELL CHOSEN)) { S t r i n g c e l l N a r n e = req.getPararneter(Screer~Narnes.CELL P A R A M ) ; rnrn. s e t C u r r e n t C e l 1 ( c e 1 1 N a r n e ) ; r e t u r n stackURL;

1 else i f

(selectedURL.equals(Screer~Narnes.PRODUCTC R E A T E D ) ) ( S t r i n g p r o d I D = r e q . g e t p a r a m e t e r ( S c r e e n N a r n e s . PRODUCT I D PARAM) ; S t r i n g p r o d N a r n e = r e q . g e t P a r a r n e t e r ( S c r e e r ~ N a r n e s PRODUCT . NAME PARAM) ; rnrn.createProduct(prodID, p r o d N a r n e ) ; r e t u r n S c r e e r i N a r n e s . CREATE ROUTING URL;
{

e l s e i f (selectedURL.equals(Screer~Narnes.CREATE ROUTING)) r e t u r ' n S c r e e n N a r n e s . CREATE ROUTING URL;

e l s e i f (selectedURL.equals(ScreenNarnes.ROUT1NG String sequence =


String action
=

CREATED))

req.getPararneter(Screer~Narnes.ROUT1NG S E Q U E N C E P A R A M ) ;

req.getPararneter(ScreerlNarnes.ROUT1NG A C T I O N S T E P P A R A M ) ;
rnrn.addRouting ( 1 n t e g e r . p a r s e I n t ( s e q u e n c e ) , r e t u r n S c r e e n N a r n e s . C R E A T E R O U T I N G URL: action);

1 else i f
String

(selectedURL.equals(Screer~Narnes.CANCEL ORDER)) 1
salesDivision
= =

req.getPararneter(Screer~Narnes.SALES D I V I S I O N P A R A M ) ;
S t r i n g orderNurnber

req.getParameter(Screer~Narnes.ORDER NUMBER P A R A M ) ; S t r i n g o r d e r T y p e = (req.getPararneter(Screer~Narnes.ORDER T Y P E PARAM) 1 ; try i


rnm. c a n c e l o r d e r ( 1 n t e g e r . p a r s e I r ~ ( tsalesDivlsior~), 1 n t e g e r . p a r s e I n t (orderNurnber)) ; prepareManageOrdersRequest(orderType, r e q ) ; r e t u r n S c r e e n N a r n e s . M A N A G E ORDERS URL; c a t c h (OrderNotCancelableException o n c e ) [ req.setAttribute(Screer~Narnes.MESSAGEA T T R I B , "This o r d e r is n o t cancelable.") ;

Capitulo 18
r e t u r n S c r e e n N a m e s .MESSAGE URL; c a t c h (NoSuchOrderException rlsoe)

req.setAttribute(Screer!Names.MESSAGE A T T R I B , " T h i s order d o e s n o t e z i s t . " ) ;


return ScreenNames.MESSAGE URL;

i
]

e l s e i f (selectedURL.tquals(Screer~Narnes.MANAGEO R D E R S ) ) { S t r i n g 0 1 - d e r T y p e = ( r e q . g e t P a r a m e t e r ( S ~ r e e r ~ N a r n. O es R D E R T Y P E PARAM) ) ; prepareMar~ageOrdersRequest(orderType, r e q ) ; r e t u r n S c r e e r r N a m e s .MANAGE O R D E R S IJRL; e l s e ~f ( s e l e c t e < J U R L .e q u a l s ( S c r e e r ~ N a m e s P . LACE O R D E R ) ) r e t u r r , S c r e e r ~ N a r n e s .P L A C E ORDER IJRL;

e l s e i f ( s e l e c t e d U R L . e q u a l s ( S ~ r e e r ~ N a m e s . O R D EP RL A C E D ) ) { t r y 1 String salesDiv = r e q . g e t P a r a m e t e r ( S c r e e r ~ I . l a m e s . 0 R D E RS A L E S D I V P A R A M ) ; S t r i n g i i r d e r N u r n = r e q . g e t P a r a m e t e r ( S c r e e r ; N a m e s . O R D E R HUM PARAM) ; S t r i n g p r o d u c t I D = r e q . g e t P a r a m e t e r ( S c r e e n N a r n e s . ORDER PROD PARAM) ; Strin:~ dateDueString = req.getPararneter(Screer~Narnes.0RDER DUE DATE P A R A M ) ; D a t e d a t e D u e = d a t e f c j r m a t . p a r s e ( d a t e C ~ u e S t r i n g ); r n m . p l a c e O r ~ A e r( I n t e g e r . p a r s e I r l t ( s a l e s D i v ) , 1 n t e g e r . p a r s e I r ~ t( o r d e r N u n ~ ) , p r o d u c t I D , d a t ?Due) ;

req.setAttribute(Screer~Narnes.MESSAGEA T T R I B ,
"Thank you for placing t h i s order.");

/
)

catch

( N o S u c h P r o d u c t E x c e p t i o r ~r l s p e )

rer~.setAttribute(ScreeriNarnes.MESSAGEA T T R I B ,
"There is n o s u c h p r o d u c t . " ) ; c a t c h (DuplicateOrderException d o e )
{

req.setAttribute(ScreeriNarnes.MESSAGE A T T R I B ,
"There is a l r e a d y a n o r d e r i n t h a t s a l e s d i v i s i o n w i t h t h a t number."); c a t c h (j ava. text. ParseException pz) I r e q . s e t A t t r i b u t e ( S c r e e n t l a r n e s .MESSAGE A T T R I B , " T h a t is r l o t a v a l i d d a t e . " ) ; S c r e e r ~ N a m e .sM E S S A G E U R L ;
{

return
]

e l s e i f ( s e l e c t e d U R L . e q u a l s ( S c r e e r ~ N a n i e s ROUTE . FOR M A N U F A C T U R E ) ) i f (rnrn. h a s l l e s t R o u t i r r g ( ) ) r e t u r n S c r e e n N a m e s . ROUTE FOR MANUFACTURE ?rRL; else r e t u r n Screer~NarvesS . H I P URL;

else i f ( s e l e c t e d U R L . etquals ( S c r e e r ~ N a m e sS . H I F PRODUCT) ) { S t r i n g l r ~ a d i r ~ g D , > c= k req.getPa1-arr~eter(Screer~Narne .S .c H I P LOADING DOCK PARAM) ; S t r i r , g c a r r i e r = r e q . q e t P a r a m e t e ~( ~ S c r e e r r N a m e s . S H I P METHOD PARAM) ; rnn:. s h i p P r o c i u c t ( c a r ~ i e r , 1 n t e g e r . p a r s e I n t ( 1 o a d i n q C c c l : l ) ; r e t u r r , S c r e e n N a m e s . rHOI1:ES URL;
{

1 else

leturn

St-reenName: . C H O I C E S U R L ;

Roles de desarrollo y de implernentacion


El m C t o d o p r e p a r e ~ a n a g e 0 r d e r s ~ e q u e s (t ) es simplemente un mCtodo de ayuda para abstraer cierta funcionalidad que haya sido utilizada dos veces:
p r i v a t e i f void

prepareMarlajeOrdersReque~t(Strir~g orderType,
{

HttpServletRequest req) ( o r d e r T y p e . e c j ~ ~ a ( lSsc r e e r ~ N a m e s ORDER . TYPE OVERDUE) ) { req.setAttribute(Screer~Names.ORDER URL A T T R I B , S c r e e n N a m e s . O R C E R T Y P E OVERDIJE) ; r e q . s e t A t t r i b u t e ( S c r e e r ~ I J a m e .s O R D E R A L T LIRL A T T R I B , S c r e e n N a m e s . ORDER T Y F E O P E N ) ; r e q . s e t A t t r i b u t e (Scree1~~N;irr1es~0RD A E LR T VIEW ATTRIB, S c r e e r t N 3 m e s . ORDER T Y P E OPEN TEXT I ; req.setArtribute(Scree1~tl.1ames.ORDER VIEW A T T R I B , S c l - e r n N 5 m e s . ORDER T ' i P E OVERDUE T E S T ) ; else // orderType e s S c r e e n N a m e s . O F : C E R T Y P E OPEN { r e q . ~ e t A t t r i b u t (eS c r e e r ~ ~ N a m e s ~ O R D E URL R ATTRIB, S c r e e n N a m e s . ORDER TY PE O P E N ) ; req.setAttributeiScreer1Names.ORDER A L T URL A T T R I B , S c r e e n N a m e s . ORDER T Y P E OVERDIJE ) ; req.setAttribute(Screer~Names.ORDER A L T V I E W A T T R I B , S c r e e r t N a m e i . ORDER T Y P E OVERDIJE T E X T ) ; r e y . s e t A t t r i b u t e ( S c r e e r ~ N a m .e O~ FPEER V I E W A T T R I B , S c r e e n N a n i e c . O R D E R T Y P E OPEN T E X T ) ;

Las constantes que utiliza la aplicacion estin definidas en la interfaz ScreenNames:

public i n t e r f a c e / / r1Jta:q ~ ' l ~ t i' c l s t a t i c f i r i a l S t r i r l g ZHOICES = " / c h o i c e s w ; p u b l i c s t a t i c f i n a l S t r i n g l E E A T E PRODUCT = " / c r c 5 t e p r o d u c t " ; c hgE A T E ROTJTING = " / c r e a t e r m ~ t i r , q " ; ~ ' u b l i cs t a t i c firjal S ~ L - i r ~ p ~ l b l i c s t a t i c f i r ~ ~ a Sl t r i r l q MANAGE O R D E R S = " / m a n a g e o r d e r z " ; f i r ~ ~ aS l t r i n g CHOOSE FOR MANIIFACTURE = " / m a r ~ u f s c t u r e c h o o s t " ; p ~ ~ b l i sc t a t i c ~ u b l i c s t a t i c f i r l a l S t r i n g ROIJTE FOR PIAIJ~JFACTURE = " / m a n u f . i c t u r e r o u t e " ; p1;blic s t a t i c f i ~ ~ b aS laceorde order"; l t r i n g P L A C E ORDER = p u b l i c s t a t i c f i n a l S t r i n g ORDER P L A C E D -= " / o r d e r p l a c e d " ; reated" ; p u b l i c s t a t i c f i n a l S t r i r i q PRODIJCT C R E A T E D = " / p r c : ~ d ~ ~ l c t ~ ~ - l b l i sc t a t i c f i n a l S t r i l ~ t qR O I J T I N G C R E A T E D = " / r i s u t i r ~ q c r e a t e d " ; ORDER c H O S E N = " / o r d e r c n ~ : , s e n " ; p u b l i c ~ t a t i cf i r l a 1 S t r i r ~ q p u b l i c s t a t i c f i r i a l S t r i n g C A N C E L ORDER = " / c a r ~ c e l c ~ r d e r " ; p u b l i , . ; s t a t i c f i n a l S t r i r l g C E L L CHOSEN = " / c e l l c h o s e n " ; p u b l i c c t a t i c firla1 S t r i r ~ q = "/ship product"; S H I P FF:OD!CT

p u b l i c p u b l i c p u b l i c publi.; p u b l i c

s t a t i c s s r s t t t t a a a a t t t t i i i i c c c c

C H O I C E S IJRL = " / ~ t ~ . ~ l i c jes sp. " ; j sp"; C R E A T E PRODLlCT IUPL = " / c r e a t e ~ r o d u c t . ? R E A T E R O U T I N G IJRL = " / c r e a t e r o u t i r ~ g j . sp"; MANAGE O R D E R S J R L = " / m a r l a q e o r d e r s . j s p " ; r H O O S E FOR MANIJFACTURE IJRL " / m a r ~ u f a c t u ~ e c h ~ j~s~ p~ " ;a e . f i r l a 1 S t r i r c g R O U T E FOR MANUFACTURE URL = "/mar~ufactl~reroute j.SF,"; f i r ~ a i S t r i r ~ gP L A C E ORDEF: U R L = " / p l a c e o r d e r . j S F ) " ; f i n a l S t r i r ~ ,M j E S S A G E lJF:L = " / m e s s a q e . j s p " ; f i n a l S t r i ! i q C H O O S E C E L L LTRL = " / c e l L i k i . j s p " ; S H I P IJRL = " / s h i p . j s p " ; firla1 S t r i r ~ q

Capitulo 18
/ / parimetros public s t a t i c final public s t a t i c final public s t a t i c final public s t a t i c final public static final public s t a t i c final public s t a t i c final public s t a t i c final public s t a t i c final
public public public public public public public public public public public public public public static static static static static static static s s s s t t t t a a a a t t t t i i i i c c c c final final final final final final final final final final final final final final

String String String String String String String String String

ORDER ORDER ORDER ORDER ORDER ORDER ORDER ORDER ORDER

TYPE PARAM = " o r d e r t y p e " ; VIEW ATTRIB = " o r d e r v i e w " ; ALT VIEW ATTRIB = " o r d e r a l t v i e w " ; ALT URL ATTRIB = " o r d e r a l t u r l " ; URL ATTRIB = " o r d e r u r l " ; TYPE OPEN = " o p e n o r d e r s " ; TYPE OVERDUE = " o v e r d u e o r d e r s " ; TYPE OPEN TEXT = " o p e n o r d e r s " ; TYPE OVERDUE TEXT = " o v e r d u e o r d e r s " ;
=

S t r i r l g SALES DIVISION PARAM S t r i n g ORDER NUMBER PARAM =

"salesdivision"; "ordernumber";

S t r i n g MESSAGE ATTRIB = " m e s s a g e " ; String String PRODUCT I D PARAM = PRODUCT N A M E PARAM "product id"; " p r o d u c t name";

S t r i n g ROUTING SEQUENCE PARAM = " s e q u e n c e " ; S t r i n g ROUTING ACTION STEP PARAM = " r o u t i n g " ; String Strir,g String String ORDER ORDER ORDER ORDER SALES DIV PARAM
=

"sales div";

N U M PARAM = " o r d e r num";

PROD PARAM = " p r o d " ; D U E DATE PARAM = " d u e d a t e " ;


=

static static static

S t r i n g CELL PARAM String String

"cell";

SHIP METHOD PARAM = " s h i p p i n g c o m p a n y " ; SHIP LOADING DOCK PARAM = " l o a d i n g d o c k " ;

La c l a s e ~ o d e l ~ a n a g es e rel proxy de nivel Web para el modelo de nivel EJB:


package import import import import import import import lmport lmport import import import import import import import import import import import factory; javax. javax. j avax. j avax. e j b . EJBException; naming. I n i t i a l C o r ~ t e x t ; naming .NamingException; r m i . PortableRemoteObj e c t ;

javax.serv1et.http.HttpSession; javax.servlet.Serv1etContext;
java.util.Date; java.uti1 .Iterator; 1 ava . u t i l . L i r ~ k e d L i s t ; f a c t o r y . m a n a g e orders.Duplicate0rderException; f a c t o r y . manage o r d e r s . OpenOrderView; f a c t o r y .manage o r d e r s . OverdueOrderView; f a c t o r y . manage o r d e r s .ManageOrders; f a c t o r y . manage o r d e r s . ManageOrdersHome; f a c t o r y . m a n a g e orders.NoSuchOrderException; f a c t o r y . m a n a g e orders.NoSuchProductException; factory.mar~ufacture.BadStatusExceptior~; factory.rnanufacture .Manufacture; f a c t o r y . m a n u f a c t u r e .Manuf a c t u r e H o m e ;

factory.order.OrderNotCance1ableException;

Roles de desarrollo y de implernentacion


p u b l i c c l a s s ModelManager { private ServletContext context; private HttpSession session;

El gestor del modelo mantiene referencias a 10s dos objetos fachada de bean de sesi6n de nuestra aplicaci6n. Obviamente, necesitamos guardar un referencia persistenteManuf a c t u r e , porque es un bean de sesi6n con estado. Podriamos volver a adquirir la i n t e r f a z ~ a n a g e ~ r d e cada r s vez que la utilicemos, lo cual puede afiadir cierto sobregasto, pero tambiin podria permitir a1 contenedor EJB realizar un equilibro de carga de un mod0 mas efectivo:
private private private private Manageorders rnanageorders; Manufacture manufacture; S t r i n g currentCellID; S t r i n g currentProductID; HttpSession session)
{

public void i n i t (ServletContext context, t h i s . session = session; this.context = context; rnanageOrders = getMarlageOrdersEJB ( ) ;
I

public void try I


j

createproduct ( S t r i n g productID,

S t r i n g productNarne)

rnar~ageOrders.createProduct(productID, p r o d u c t N a r n e ) ; .
c u r r e n t P r o d u c t ID = p r o d u c t I D ; c a t c h ( j a v a . rrni. R e r n o t e E x c e p t i o n t h r o w new E J B E x c e p t i o n ( r e ); re)

public String getcurrentcell ( ) return currentCellID;

I
p u b l i c void setCurrentCell(String currentCellID = currentCel1; currentCel1)

I
public S t r i n g getCurrentProductID( ) return currentProductID;
[

p u b l i c void a d d R o u t i n g ( i n t sequence, S t r i n g a c t i o n ) { try i rnanageOrders. a d d R o u t i r ~ g I r i s t r u c t i o r (~ currer~tProductID, sequence, a c t i o n ) ; 1 c a t c h ( j a v a . rrni . R e r n o t e E x c e p t i o n r e ) { t h r o w new E J B E x c e p t i o n ( r e ) ;

public

void

p l a c e O r d e r ( i n t s a l e s D i v i s i o n , int orderNurnber, S t r i n g p r o d u c t , Date dateDue) throws NoSuchProductException, DuplicateOrderException orderNurnber,


{

try
}

rnanageOrders.placeOrder(salesDivision,
catch throw ( j a v a . rrni. R e r n o t e E x c e p t i o n new E J B E x c e p t i o n ( r e ) ; re)

product,

dateDue);

Capitulo 18

public void cancelOrder(int salesDivision, int orderNumber) throws NoSuchOrderException, OrderNotCancelableException { try manageorders. cancelOrder (salesDivision, orderNumber) ; catch ( java. rmi. RemoteException r e ) { throw new EJBException ( r e );

1
public synchronized Iterator getOrdersToManufacture ( ) { try I LinkedList list = new LinkedList ( ) ; manufacture = getManufactureEJB( ) ; OpenOrderView [ 1 openorders = manufacture. qet0per~Orders ( ) ; for (int iter=O; iter<openOrders. length; itertt) [ list .add ( n e w OrderView(open0rders [Pter]) ) ;

1
}

return list. iterator ( ) ; catch ( j ava. rmi. RemoteException r e ) { t h r o w n e w EJBException ( r e );

I
public synchronized void selectForManufacture(int salesDiv, int orderNum) throws NoSuchOrderException, BadStatusException { try i manufacture. selectForManufacture ( s a 1 e s D i v orderNurn) ; 1 catch (java .rmi.RemoteException r e ) t t h r o w n e w EJBException ( r e ); 1 public synchronized boolean hasNextRouting ( ) { try i r e t u r n manufacture. hasNextRoutir~g ( ) ; 1 c a t c h ( factory .manufacture .NoSelectionException n s e ) { t h r o w n e w EJBException ( n s e ); ] catch ( j ava. rmi . RemoteException r e ) { t h r o w n e w EJBException ( r e ); 1 public synchronized Strir~g getNextRouting ( ) { try I r e t u r n manufacture. qetNextRouting ( ) ; 1 catch ( factory.manutacture. NoSelectionException n s e ) { t h r o w n e w EJBExcept ion (r,se) ; ) catch (java.rmi.RemoteException r e ) { t h r o w n e w EJBException ( r e ) ;

I
1
public synchronized void shipProduct(String carrier, int 1oadingDock) try I manufacture. ship(carrier, 1 o a d i n g D o c k ) ; 1 catch (factory.manufacture.NoSelectior~Exceptior nsel { t h r o w n e w EJBException (rise); ) catch ( j ava. rmi. RemoteException r e ) { t h r o w n e w EJBException ( r e );
{

I
i

Roles de desarrollo y de implernentacion

public Iterator getorders (String type) [ try i L i n k e d L i s t l i s t = new L i n k e d L i s t ( ) ; i f ( t y p e . e q u a l s ( S c r e e r ~ N a m e.ORDER s TYPE OPEN TEXT) ) { Openorderview[] o p e n o r d e r s = manageorders .getSchedulableOrders f o r ( i n t i t e r = O ; i t e r < o p e r ~ O r d e r sl.e n g t h ; i t e r t t ) [ l i s t . a d d ( n e w O r d e r V i e w ( o p e n 0 r d e r s[ i t e r ] ) ) ;

( ) ;

1
)

e l s e i f ( t y p e . e q u a l s ( S c r e e n N a m e s .ORDER TYPE OVERDUE TEXT) ) { OverdueOrderView [ ] overdueOrders = mar~ageordersg . etOverdueOrders ( J ; f o r ( i n t iter=O; iter<overdueOrders. length; i t e r + + ) { l i s t . a d d ( n e w OrderView(overdueOrders[iter]));
J

e l s e t h r o w new I l l e g a l S t a t e E x c e p t i o r ~ ( ) ; return l i s t . i t e r a t o r 0 ; c a t c h ( j a v a . rmi . R e m o t e E x c e p t i o n r e ) { t h r o w new E J B E x c e p t i o r ~ ( r e );


}

I
1

Finalmente, tenemos algunos mktodos de ayuda:


p r i v a t e Marlageorders getManageOrdersEJB( ) { try I I r ~ i t i a l C o r ~ t e xi tn i t i a l = new I n i t i a l C o n t e x t ( ) ; O b j e c t o b j r e f = i n i t i a l . lookup ( " j a v a : comp/er~v/ejb/Mar~ageOrders; ") ManageOrdersHome home = (ManageOrdersHome) PortableRernoteObj e c t . r i a r r o w ( o b j r e f ,

ManageOrdersHome.class);
]
)

return catch throw catch throw catch throw

home. c r e a t e ( ) ; ( N a m i n g E x c e p t i o n rle) [ new E J B E x c e p t i o n ( n e ) ; ( j a v a . rmi . R e m o t e E x c e p t i o r ~ r e ) { new E J B E x c e p t i o n ( r e ); ( j a v a x .e j b . C r e a t e E x c e p t i o r ~ c e i { new E J B E x c e p t i o n ( c e ) ;

1
1

p r i v a t e Manufacture getManufactureEJB ( ) { try I I n i t i a l C o n t e x t i n i t i a l = new I n i t i a l C o n t e x t ( ) ; O b j e c t o b j r e f = i n i t i a l . l o o k u p ( " j a v a : c o m p / e r ~ v / e j b / M a r ~ u f a c t u r e "; ) Manuf a c t u r e H o m e home = (Manuf a c t u r e H o m e ) P o r t a b l e R e r n o t e O b j e c t . n a r r o w ( o b j r e f , ManufactureHome. c l a s s ) ; r e t u r n h o m e . c r e a t e ( c u r r e r ~ t C e l l I D; ) I c a t c h (NamingException n e ) { t h r o w new E J B E x c e p t i o r l ( n e ) ; ) c a t c h ( j a v a . rmi . R e m o t e E x c e p t i o n r e ) { t h r o w new E J R E x c e p t i o n ( r e ) ; ) c a t c h ( ja v a x . e j b . C r e a t e E x c e p t i o n c e ) { t h r o w new E J B E s c e p t i o n i c e ) ;

1
}

Utilizamos una clase de vista para devolver informacibn del modelo a las diversas vistas JSP. La vista es bisicamente un simple contenedor para la informacibn:
package factory;

Capitulo 18
import java. ut il. Date; import factory. manage orders. OpenOrderView; import factory. manage orders. OverdueOrderView; public class Orderview { private int salesDivision; private int orderNumber; private String product; private String status; private Date dateDue; public OrderView(1nt salesDivision, int orderNumber, String product, String status, Date dateDue) this. salesDivision = salesDivision; this.orderNumber = orderNumber; this.product = product; this.status = status; this.dateDue = dateDue;
{

I
public O r d e r V i e w ( O p e r 1 0 r d e r V i e w view) { this(view.salesDivision, view.orderNumber, view.product, "open", view.dateDue) ; public OrderView(Overdue0rderView view) { this(view.salesDivlsion, view.orderNumber, view.product, view.status, view.dateDue); 1 public Orderview( )
( )
( )

public int getSalesDivision return salesDivision;

I
public int getOrderNumber return orderNumber;
1
( )

public String getproduct return product; public String getstatus return status; 1

( )

( )

public Date g e t D a t e D u e 0 returr, dateDue; 1

La vista "rnenGprincipal"es proporcionada por choices. j s p :


<html> <head> <title>Wrox Sample Code / J2EE</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-l"> </head>

Roles de desarrollo y de implementation


<p>Choose <ul> <li><a <li><a <li><a <li><a one of the following actions: </p>
h r e f = " c r e a t e p r o d u c t " > C r e a t e a sample product</a></li> href="placeorder">Place a sample order</a></li> href="manageorders?ordertype=openorders"Manaqe orders</a></li>

href="manufacturechoose">

Manufacture a product f o r an order </a:,</lii </ul> <p>&nbsp; < / p > </body> i/htrnl>

La vista "crear un producto" es asi:

+ei5,--+-Qma1a~m

Archo

EdicltKl

VCT

Fawritos

Herramentas

Ayuda

Q F ~ O S

~ ~ m e b a

aIi&aajGJg

La vista es proporcionada por createproduct . jsp:


<html> <head> <title>Wrox Sample Code Create a Product</title> <rneta http-equiv="Content-Type" content="text/html; charset=iso-8859-l"> </head>

<body bgcolor=" H FFFFFF1'> <p>Create a product:</p> < f o r m method="post" action="product createdN> <p>Product ID <input type="textW name="product id"> </p> <p>Product Name <input type="textl' name="product name">
</p>

ip> <input type="submitn name="Submitn value="Submit"> </p> </form> <p>&nbsp; </p> </body> </htrnl>

Capitulo 18
Despuks de ahadir un producto, podernos ahadir pasos de redireccionarniento:

Archivo

4-

. i i r 3s

-*-@

Ed~iCln Ver

Favorites

Herramientas a~kquede

Ayuda Favoritos f@~ultimedia


. . . . . . p p . . .

1
. .

a / Q- a
. . . . . .. . . .-

= I

. . .

)irecci6nI& http:~/localhost:7001~FactorylcontroVprreated

P I~

Create a rouSequence 101 Rouk

for product LAMP05:

. -

Solder the bottom metal piece of the lamp to the top metal piece

or you can be firuslled wth c r e a m roubngs for this produi t

La vista para ahadir 10s pasos de redireccionarniento es proporcionada por create routing. j sp:
< jsp: useBean

id="modelManager" class="factory.ModelManager" scope="session"

/>
<html> <head> < t i t l e > W r o x S a m p l e C o d e - Create a Routing</title> < m e t a http-equiv="Content-Type" content="text/html; charset=iso-8859-l"> </head> <body bgcolor=" #FFFFFFn> < p > C r e a t e a routing for product

<%=modelManager.getCurrer~tProductIDO%>: </ p>


<form method="post" action=" routing c r e a t e d u > <p>Sequence <input t y p e = " t e x t W name="sequence"> </p> <p>Routing <textarea name="routing" cols="75" rows="lOW></textarea>

Roles de desarrollo y de implernentacion


-up,, ip') ~ : i n ~ ' utty p e = " s u b m i t " narne="Submitl' v a l u e = " S u b r n i t " : ~ up> </form> < p > o r you c a n b e < a h r e f = " c h o i c e s " > f i n i s h e d w i t h c r e a t i n g r o u t i r ~ g s for t h i s p r o d u c t < / a > . < / p >
</body>

i/html>

Puede realizar un pedido:

Archivo

Edici6n

Ver

Favoritos

Herramientas

- -

Ayuda
-

81

Place an order for a product:

Sales division 101

Order number 1 11

Esta funcionalidad es proporcionada p o r p l a c e h o l d e r . j sp:

< t i t l e > W r o x Samole Code

Place an O r d e r < / t i t l e >

< b o d y b g c o l o r = " iFFFFFF1'> < p > P l a c e an o r d e r f o r a p r o d u c t : < / p > <form method="post" a c t i o n = " o r d e r placed" +>Sales d i v i s i o n < i n p u t t y p e = " t e x t M name="sales d i v W > </p> <p>Order number

name="Place0rdert'>

Capitulo 18
<input type=" text" name="order n u m m >
</p>

<p>Product <input type="textW narne="prodN> </p' <p>Due date <input t ype="textW narne="due date"?
s:/p>

<p> ,:input
i / p>

type="submit"

name="Submit"

value="Submit">

</ fc.rm>
<p>&nbsp; < / p > </body> </html>

Despues de haber realizado un pedido, se rnuestra un rnensaje de agradecimiento, proporcionado por


message. j sp:

rim

Edici6n

Ver

Favoritor

Herramientas

Ayuda

Thank you for placing this order..


Return to rnain m e r u
tisto

1-

II
[@~ o c intrenet a~
A

<html> <head> < t i t l e > W r o x S a m p l e C o d e - Message</ title> <meta http-equiv="Content-Type" content="text/html; </head>

charset=iso-9859-l">

< p > < a href="choices">Return


</body>

t o m a i n rnenu.</a></p>

c/html>

Existen dos versiones de la vista de gesti6n de pedidos, una para pedidos abiertos y otra parapedidos atrasados. Cualquier pedido de la lista puede ser cancelado haciendo clic en un hipervinculo. Esta es la vista de pedido abierto:

Roles de desarrollo v de im~lementacibn


--lalxl -I

1 , -

. a .

--

1 -

Archivo

+fit135

- + -ia rn

Edicih

Ver

Favo~ 4tos

Mrramientas

Ayuda

Neccih

http://localhost:700~

You are currently mevmg open orders Chl:L, here to mew overdue orders
D -v o i s i i n -

larder ~ u r n b e r

c to Cancel k

8-ehrn to m a i n menu

~ s t es a la vista de pedido atrasado:

Arch~o

c isirx

-+-

Ed1cb-1 Vsr Favorites Herrermentas Ayuda @ taBbqueda @Favorites Q M u l t ~ ~ ~ d i a

aI

1 a-a a

IIrI

Manage Your Orders You are currently mewing overdue orders CLck here to view open orders.
--

]sales Division

Order Number

F r o d u c t /DateDue F

c!~

11

Arnbas versiones de la vista son proporcionadas por manageorders .j sp:

Capitulo 18

< % @ page
< % @ page

import="java.util.Iterator" % > import=" factory .OrderViewM % >

<html> <head> <title>Wrox Sample Code - Manage Orders</title> <meta h t t p - e q u i v = " C o r ~ t e r c t - T y p e " content="text/html; </head> <body bgcolor="#FFFFFF"> <p>Manage Your Orders</p>

charset=iso-8859-l">

<p>You are currer~tly viewing < % = request.getAttribute("order viewn)%>. <a href="manageorders?ordertype=<%= request.getAttribute("order alt urlW)%>"> Click here to view '<%= request.getAttribute("order alt view") % > . </a> </p> <table width="87%" border="lW> <tr> <td width="21%">Sales Division</td> <td width="23%">0rder Number</td> <td width="19%">Product</td> <td width="16%">Date Due</td> <td width="21%">Click to Cancel</td> </tr>
<%

String orderview = (String) request.getAttribute("order view"); Iterator iter = modelManager.get0rders (orderview); while (iter.hasNext ( ) ) {. OrderView view = (OrderView) i t e r . n e x t 0 ;
%>

<tr> <td width="2l%"><%=vie~.getSalesDivisior~()%></td> <td width="23%"><%=vie~.getOrderNumber()%></td> <td width="l9%"><%=vie~.getProduct()%></td> <td width="l6%"><%=vie~.getDateDue()%></td> <td width="Zl%"><a h r e f = " c a r ~ c e l o r d e r ? s a l e s d i v i s i o r ~ = < % = v i e w . getSalesDivision()%>&orderr~umber=<%=view.getOrderNumber() %>&ordertype=<%=request.getAttribute("order urln)%>">cancel</a></td> < / t r>
< % )% >

</table> <p>&nbsp; <a href="choices">Return </body> </html>

to main menu</a></p>

En la siguiente vista, puede elegirse un pedido para su fabricacibn:

Roles de desarrollo v de implementaci6n

Archivo

EdicrCKl

Ver

Favorttos
-

Herramientas

Ayuda

-- -----

\ m a

II

Choose an order to manufacture:

Wed Aug 01

Desk Lamp

00.00:00 BST 2001

L?vista es proporcionada pormanuf a c t u r e c h o o s e .j s p :

.:body b g c c ~ l o r = " % FFFFFFM> cpSChouse a n t c r d g r to r n a n u f a c t u c f : < / p : l 'table width="P7?" h r d e r = " l 1 ' > c t r-> ctd w i d t h = " 2 1 8 " > S a l e ? D i v i s i o n < / t d i I td w i d t h = " 2 3 $ " > O r d o r Number</td> < t d w i d t h = " l ~ % " > P r o d u c t it /d > it[$ w i m A t h = " 1 6 4 " > D a t e D u e < / t d b

c:/tr;

< ?,
I t e r a t w r iter = m o d e l M a n a q e r . g e t O r d e r s T n t 4 a r ~ u f a c t u r e ( i ; w h i l e liter.hasNest0) I O r d s r V i e w view = ( O r d e r v i e w ) i t e r . r~ext l) ;

n . . % , ,

<tr>

C t d ~ . ~ i d t h = " Z 1 % " > < % = v i e w . q e t S a 1 e s D 1 v i s ij ~ %~ >r <1 /lt d > <td width="Z3%">ia h r e f = " o r d e r c h r ~ s e n ? s a l e s d i v i s i o n = c%=view.qetSalesDivi~ion[)~>&orderr~umbec=<%=view.g~tOrderN~mberi $>"> <%=view.getOrderNumber()%></a></td> <td w i d t h = " 1 8 8 " > < % = v i e w g . etpr~duct ( 1 %></td> <td width="16R">i4=vie~.getGateDue [ ) % > < / t d >

Capitulo 18

La prinlera vez que el usuario intenta elegir un pedido para su fabricncion, se le pedirii que introduzca un nilmero de ID de cClula para identificar el Area e n la que el producto estii siendo fabricado (es decir, que s e registre):

Enter your current manufachirug cell identlGcation shmg:


. ... . .. . .. ... .. . ,.,

ICELLZ

....

ist to

rr/@~ocal

intranst

LJ siguiente pigina JSI'es utilizada para identificar al usuario. Los tipos de usuario e n el nombre de su cClula y la Eecha d e prebentacibn de formulario son llevados a 105 principales servlets:
,-i~trnl> .:head:, < t i t l e > P I r n x S a m p l e Code E r l t ~ r Ycur C e l l I D < / t i t l e ' . <meta h t t ~ > - e , q u i v = " C o n t . e r ~ t - T y p e " c o n t e n t . = " t e x t / h t m l ; charr.et-iso-RH.50-1":</head>

ct~ody h g c ~ ~ l o ri = l FFFFFF1'> " < p > L c ~ q i r< ~/ : p> <fern1 mett,od="puct1' a c t i ~ r ~ = " c e c lh l ,3senu> <p?Enter your current. manufacturing c e l l <input t y p e = " t e x t n name="cell">

identification s t r i n g :

'F'

</F:,
"

/ i n p u t type="submlt" </p> </form? <p>,snhsp; </p> --:/body'

name="Suhmit"

val~~~="Sub t"', mi

c/html>

Una vez que un pedido ha sido elegido para ser fabricado, 10s pasos de redireccionamiento son ~ n o s t r a d o s sucesivan~ente:

Roles de desarrollo y de implementacibn

Archive

Edici6n

Ver

Favorites

Herramkctar

Ayuda

Here is the next step in the manufacture of this product: Solder the large metal plate to the base of the lamp.

Click here when completed.

La vista es proporcionada p o r m a n u f a c t u r e j sp:

< t i t l e > W r o x S a m p l e C o d e - Routing Step</title> <meta http-equiv="Content-Type" content="text/html; </head>

charset=iso-8859-l">

<body bgcolor="#FFFFFF"> < p > H e r e is t h e n e x t s t e p i n t h e manufacture o f this product:</p> <p><jsp:getProperty name=nmodelManagern property="nextRouting"/></p> < p > < a href="manufactureroute">C1ick h e r e w h e n completed.</a></p> <p>&nbsp; < / p > <p>&nbsp; </p> </body> </html>

Finalrnente, despuis de que se hayan rnostrado todos 10s pasos de redireccionarniento, se introduce la inforrnaci6n de envio:

Capitulo 18

li-

1
]

Archlvo

C AtrBs

- +-@a ,
-

EdkltKl

Ver

Favoritos

HerrMnientas

Ayuda

@Bisque&

Favoritos C@~ultimedia

aI 1 @1
r

II

S h p the manufactured product:

La vista es proporcionada por s h i p . j s p :


<html> <head> <title>Wrox Sample Code

Ship the Product</title>

<body bgcolor="#FFFFF"> <p>Ship the manufactured product: </p> <form met hod="postV act ion="ship product " > <p>Shipping company: <select name="shipping company"> <option>UeS</option> <option>Federal Express</option> <option>lJS Postal Service</option> <option>Private Carrier</option> </select> </p> <p>Loading dock: <input type="textn name="loading docku> </p> <P> <input type="submitn name="Submit" value="Submit"> </p> </form> <p>&nbsp; </p> </body> </html>

Proporcionamos un archivo HTML que puede ser utilizado como archivo de bienvenida para esta ap~icaci6r1,~larnadoindex. html:
<html> <head> <title>Wrox Sample Code - Manufacturing Application</title>

Roles de desarrollo y de implementaci6n


,'./hea.j? <body text="#000UOG" b q c a l o r = " # F F F F F F " lir1k="#0000EE" vlir1k="#55lARR" alink="RFC100~"> <center:, < h l > F a c t o r y Demo f o r J S F s a n d E J B s < / h l > </center? <center>ihr width="lOO%"></center> < p - . T h i s PJeb s i t e p r o v i d e s a s i m p l e i r ~ t e r f a c e to t h e m a n l d f a c t u r i n g e x a m p l e t h a t w e d e v e l c p e d f o r t.hc c h a p t e r s on E n t e r p r i s e J a v a B e a n s i n t h e It:r,:,x S e r v e r S i d e J a v a book.-:/p>
.:p,.<a

h r r f - " c o r ~ t . r o l / c h o i c e s " > S e e t h e d e n i n . . .</a,,

La pantatla de bienvenida es como ista:

Thts web site provides a sunple interface to the manufacturing example that we developed for the chapters on Enterprise JarraBeans in the Wrox Server Side Java book.
S e e the demo .

Los componentes Web son recogidos en un WAR. Este archivo Web tiene un descriptor de implementaci6n web. xml,localizado en WEB-IN??, que especifica el archiv? de bienvenida, el/los sewlet/ s, la asociacion de URL a sewlets y las referencias a Enterprise JavaBeans. Este es el archivo Web. xml:

-:!DOCTYPE

Web-app PIJBLIC "-//Sun M i c r o s y s t e m s , Inc.//WTD Web A p p l i c a t i o n 2.3//ENW "http://java.sun.c0m/dtd/app1icatiori 1 3.dtdW>

Capitulo 18

Para implementarlo en WebLogic necesitamos un archivo weblogic. xml en el directorio WEB- INF:
< ! D O C T Y P E weblogic-Web-app PUBLIC "-//BEA S y s t e m s , I n c . / / D T D W e b A p p l i c a t i o n 6.O//EN8' "http://www.bea.com/servers/wls6l0/dtd/ weblogic-Web-jar.dtdW>

La estructura de directorio del archivo Web ( j s p s .war) es la siguiente:


cellid.jsp choices.j sp createproduct. jsp createrouting. jsp index. html main. j s p manageorders. jsp manufacturechoose. jsp manufactureroute. jsp message. j s p

Roles de desarrollo y de implernentacion


placeorder. j sp ship.jsp WEB-INF/ Web. xml w e b l o g i c . xrr~l classes/
fact;,^

y/ Mixi?ltlar~agerc . lass O r d e r V i e.d. c l a s s Request P r o c e s s o r . c l a s s ScreenNarnes.class

Este archivo Web es ariadido a un EAR en el mismo nivel que el archivo EJB. Debemos ariadir referencias a ambos en el archivo estindar J2EE a p p l i c a t i o n . xml. Suponiendo que el JAR de EJB (o directorio, si su servidor de aplicaci6n es compatible con este formato) es denominado e j b s . j a r y el archivo Web (0 directorio) es denominado j s p s . w a r (observe que estos nombres son arbitrarios), el archivo a p p l i c a t i o n . xmlseriasi:
<?xml v e r s i o n = " l . 0" encoding="UTF-b"?> < ! DOCTYPE a p p l i c a t i o n PUBLIC ' - / / S u r ~ micro system.^, I n c . //DTD J2EE A p p l i c a t i o n 1.2//EN1 ' h t t p : / / j a v a . s u n . com/j 2 e e / d t d s / a p p l i s a t i m 1 2 . d t d 1 > <application; <display-narr~e~</dis~lay-r~arne> <module> < e j b > e j ts. j a r < / e j h> </module> <module> <Web> < W e b - u r i \ j s p s :xar</Web-uri>

<ccnt?xt-root\factory</context-root>
</Web\ </m.>dule> </application>

Una vez ha sido desplegado el EAR, podemos ponerlo a prueba navegando hasta http://localhost:700Y factorylindex. htrnl.

Consejos para resolver problemas


Escribir software de empresa es un proceso dificil, independientemente de las herramientas y tkcnicas utilizadas. Mis tarde o mis temprano, nos encontraremos con un servidor de aplicaci6n que no podemos conseguir que funcione, un EJB que no se implements o una aplicacion que sirnplemente no funciona como debe. A menudo nos llevari horas o incluso dias arreglar el problema. Estos son algunos consejos para enfrentarse a algunos de 10s problemas mis comunes:
0

Estemos escribiendo una aplicaci6n compleja o simplemente un finico componente EJB, necesitaremos ejecutar repetidamente el ciclo de desarrollo-ensamblaje-implementaci6n-prueba. Este proceso puede ser lento e irritante asi que es mejor automatizarlo tanto como sea posible. Esta automatization puede alcanzarse utilizando un buen IDE o una herramienta como Ant. Ant es el sistema integrado de Java del Proyecto Jakarta (disponible en http://jakarta.apache.orglant/ index.htrnl).

0 Lea siempre la documentaci6n adjunta a1 servidor de aplicaci6n. Aunque esto pueda parecer obvio, es importante recordar que 10s servidores de aplicaci6n pueden tener sus propias peculiaridades y trabas. Una exhaustiva lectura de la documentaci6n puede alertarle con antelaci6n sobre problemas potenciales.

Capitulo 18
Intente ejecutar el sewidor de aplicacion en el mod0 de depuracion. La mayoria de 10s servidores de aplicacion tendrin este rnodo y, si el suyo no lo tiene, siernpre puede ejecutar la aplicacion en uno que si lo tenga. Sin embargo, es una buena prictica no recurrir inmediatamente el depurador cuando tenemos un problema. Intentando resolver el problerna a travks de la inspection del codigo, podemos mejorar nuestra compresion de conjunto de la aplicacion y su codigo, lo cual puede ayudarnos a resolver futuros problemas con mayor rapidez. TambiCn deberiamos tener en cuenta que depurar todos 10s componentes EJB puede resultar dificil con un depurador de aplicaci6n. Examinar el c6digo puede modificar el comportamiento de nuestros componentes: desde "arreglar" gazapos de sincronizaci6n, hasta provocar que expire una transaction. Escribir informaci6n en un registro es, a menudo, un mod0 menos agresivo de ver qu6 esti ocurriendo. Algunos sewidores de aplicaci6n proporcionan optimizaciones de propiedad, como comprobar un metodo isModif ied ( ) antes de sincronizar el estado de un bean de entidad con la base de datos. Intente desactivar estas optirnizaciones antes de ver si ha cometido un error en su uso. El archivo de registro del servidor de aplicacion puede ser una rica fuente de inforrnacion. Un claro mensaje de error o una obvia traza de pila puede, a menudo, apuntar a la causa del problema. Como regla general, cuando capturamos una excepcion no esperada, es Gtil imprimir un rastreo de pila antes de volver a generar la excepcion. Esto provocari que se realice una entrada en 10s registros del servidor de aplicacion, que puede resultar Gtil en la resolution del problems. Si un JAR EJB no se implements, debemos sentirnos aliviados porque este tip0 de problems es a rnenudo mucho mis ficil de resolver que un error de period0 de ejecucion. El servidor de aplicacion debe proporcionarnos un Gtil mensaje de error que nos ayude a identificar el origen del problema. Algunas soluciones para algunos de 10s problemas mis comunes consisten en asegurarnos que nuestros m6todos de retrollamada y datos de entidad C M P son declarados p6blicos y asegurarnos que el descriptor de implementation se encuentra en el directorio METAINF.

Si todo lo demis falla, merece la pena implementar el JAR en un servidor de aplicacion diferente. Quizis el problema sea del servidor de aplicacion, en lugar del cbdigo.

Hemos visto en este capitulo que existen cinco roles definidos en la especificacion Enterprise JavaBeans, c ~ r r e s ~ o n d i e n ta es actividades que deben ser ejecutadas para un efectivo desarrollo, implementacidn y mantenimiento de una aplicacion de base EJB:

13 El desarrollador de bean proporciona 10s cornponentes EJB para una aplicacion. El sewidor de aplicacion proporciona diversos servicios y, por ello, el desarrollador de bean no tiene necesidad de escribir c6digo para apoyar transacciones, concurrencia, seguridad, comunicaci6n, manejo de errores mis a116 del sistema de excepciones de una aplicacion, equilibrio de carga, relevo o incluso persistencia, de hecho, el desarrollador de bean ni siquiera necesita ser un experto en el entorno operativo de destino. 13 El ensamblador de la aplicacidn combina EJB (procedentes de uno o mas desarrolladores de bean) en una aplicacion que se puede implernentar. El descriptor de irnplementacibn proporcionada por

Roles de desarrollo y de implernentacion


el desarrollador de bean tiene informaci6n afiadida de nivel de aplicaci6n. En esta fase, el ensamblador de la aplicaci6n tambikn puede afiadir otros tipos de componentes de aplicaci6n, como senlets, piginas JSP o aplicaciones cliente. El ensamblador de la aplicaci6n no necesita comprender la implementaci6n de 10s EJB. Sin embargo, si es necesario que comprenda el contrato que representan las interfaces inicial y remota, asi como la 16gica de empresa que ejecuta el EJB.
0 Una vez completada la aplicaci6n, se implementa en el entorno de destino. Las referencias 16gicas

utilizadas por el implementador de bean deben asociarse a recursos o identidades reales. Este paso es especifico de un senidor de aplicaci6n concreto. U n implementador no necesita ser un experto de campo, sino un experto en el entorno en que se ejecutari la aplicaci6n.

0 El administrador del sistema es responsable de configurar el senidor de aplicaci6n y el contenedor EJB, asi como el entorno en el que se ejecutan. El administrador del sistema tambikn es responsable de controlar registros para cualquier problema de sistema o de seguridad.
0 U n vendedor de terceros proporcionari el senidor de aplicacidn/contenedor EJB. La selecci6n de un senidor de aplicaci6n adecuado para el desarrollo y la implementaci6n es importante para el Cxito de la aplicacidn y debe tener en cuenta varios factores como coste, apoyo y adaptacidn a la especificaci611, asi como funciones opcionales que podria proveerse.

Recuerde que estos roles son conceptos abstractos y que el personal que 10s ejecuta en un equipo real de desarrollo de aplicaci6n puede desempefiar mdtiples roles; o puede que se necesiten varias personas para desempefiar un h i c o rol. Tambikn hemos desarrollado una aplicaci6n JZEE completa, concluyendo la aplicaci6n de fabricaci6n que habia sido construida anteriormente. Hemos utilizados dos de las tecnologias de empresa mis importantes (EJB y senlets) asi como algunas auxiliares USP, J N D I y seguridad). En el siguiente capitulo conoceremos un nuevo tip0 de Enterprise JavaBean, el bean controlado por mensaje. A medida que vayamos aprendiendo c6mo utilizar estos nuevos beans, tambikn conoceremos el Senicio de Mensajes Java y aprenderemos c6mo crear aplicaciones para utilizarlo.

JMS y beans controlados por mensaje


En este capitulo, examinaremos el servicio de mensajes Java, Java Messaging Service (JMS), y 10s Enterprise JavaBeans controlados por mensaje, Message-Driven Enterprise JavaBeans (MDB). JMS combina tecnologia Java con mensajes de empresa para formar una s6lida herramienta para resolver problemas de procesamiento distribuido de empresa y esti acelerando el uso de Java en nuevas ireas, igual que ocurri6 con la introducci6n de JDBC en 10s origenes del lenguaje. Comenzaremos revisando c6mo se ha utilizado en el pasado la tecnologia Message-Oriented Middleware (MOM), software intermediario orientado hacia el mensaje, y c6mo se utiliza hoy. Esto nos permitiri ver que, lejos de reemplazar las antiguas tecnologias de mensaje, JMS en carnbio aumentari su uso, ya que se esti convirtiendo en el estindar de industria para API de mensaje. Despuks seguiremos analizando c6mo JMS puede manejar llamadas asincronas entre aplicaciones distribuidas. DespuPs de analizar varios ejemplos JMS, estudiaremos beans controlados por mensaje, recientemente introducidos en la especificaci6n EJB 2.0. Aprenderemos c6mo construir un bean de este tip0 y comprenderemos c6mo puede participar en transacciones utilizando el Java Transaction API (JTA). Los ejemplos de este capitulo han sido desarrollados y probados con la Implementaci6n de Referencia JZEE, versi6n 1.3. Sin embargo, deben funcionar en la mayoria de implementaciones JMS independientes con Doca o ninauna modificaci6n en el c6diao. Se indicari cualouier funcionalidad exclusiva a la implementaci6n de referencia. Los beans controlados por mensaje requieren una implementaci6n J2EE 1.3, igual que la integraci6n JMS con JTA.

Ademis de la implementaci6n de referencia, el c6digo de ejemplo JMS funcionari con un ligero carnbio en las siguientes implementaciones JMS:
0
0

SwiftMQ disponible en http://www.swiftmq.com/ SpiritWAVE disponible en http://www.spirit-soft.com/

Capitulo 19
O

SonicMQ disponible en http://www.sonicsoftware.com/

Siempre que sea posible, es preferible utilizar la implementation de referencia de Sun, ya que podri ejecutar el c6digo de ejemplo sin modificaciones.

Como desarrolladores, tenemos una amplia opcidn de proveedores JMS (hay mas de una docena de implementaciones de peso en la industria). Utilizaremos implementaciones independientes y autdnomas, en lugar de utilizar JMS empaquetados como parte de un Servidor de Aplicacidn. Esto excluye a 10s JSM similares de IBM, Oracle, SilverStream, Allaire y BEA, pero no son, en absoluto, versiones inferiores.

Breve historia del mensaje


Los ordenadores conectados a una red tienen interfaces de mod0 que pueden comunicarse entre ellos. Crear estas interfaces implica muchas cuestiones, incluido:
0 0

iComo podemos garantizar una conexi6n fiable entre emisor y receptor? iC6mo empaquetamos el mensaje?

0 iQu6 sucede si falla la red?

Tres de 10s primeros metodos que se utilizaron para conectar ordenadores son:
O RS232

Un conector en seriel estindar, todavia utilizado en la actualidad para comunicar con modems. Era un mod0 muy comun de proporcionar comunicaci6n basada en mensajes entre dos sistemas cualquiera durante 10s ahos setenta. La mayoria de protocolos que utilizan RS232 son asincronos; el receptor tenia que estar recibiendo activamente a1 mismo tiempo que el emisor enviaba el mensaje. Esto es obviamente bastante restrictivo y provoca que las aplicaciones en comunicaci6n seacoplen fuertemente.
0 Protocolo de Transferencia de Ficheros (FTP)

Este sencillo protocolo no proporciona un medio para sincronizar transferencias de archivo basadas en equipos; el receptor nunca sabe si el emisor ha terminado de enviar su mensaje ni cuando lo ha enviado. FTP fue disehado para transferir archivos, aunque no existe ninguna restricci6n en cuanto al contenido de 10s archivos.
0 E-mail

Como FTP, es mas adecuado a la interaction humana que la transferencia de mensajes basada en equipos, ya que no existe ningun estindar definido para reconocer la recepci6n de un e-mail, por lo que existe forma alguna de saber si un e-mail recibido. El protocolo Post Office Protocol (POP) proporciona mensajeria asincrona separando 10s requisitos que ambas miquinas necesitan para estar activas durante la transferencia del mensaje. Esta forma de intercambio de mensajes se define como dibilmente acoplada. Una aplicacion que requeria tecnologia de mensajeria podia utilizar diferentes paquetes de protocolos y mensajeria adquiridos, cada uno de ellos con sus ventajas e inconvenientes. Con frecuencia, un equipo de desarrollo de una compaiiia optaria por implementar una soluci6n de empresa que afectarh a toda la compahia en lugar de comprar estas tecnologias. Mis recientemente, la llegada de las tecnologias MessageOriented Middleware (MOM), como MQSeries de IBM y Rendezvous de TIBCO, ha permitido a las organizaciones implementar una capa de transporte de mensajes garantizada, segura, en la que pueden basarse mis ficilmente las estrategias de integracih de sistema de alcance de empresa.

JMS v beans controlados por mensaje


MQSeries y Rendezvous son las tecnologias mks comtinmente utilizadas, permitiendo a casi cualquier sistema conectar y comunicar de forma fiable con prkcticamente cualquier otro sistema. Existen otros que se ajustan a menudo a verticales especijicas y proporcionan mks funciones donde se necesitan.
Utilizando estas tecnologias de capa de transporte con10 base, muchas compafiias han producido 10s llamados sistemas de software intermedio de "intermediario de mensaje" (basados en MOM), que ofrecen una combinaci6n de transformaci6n de datos y entrega de servicios construida sobre 10s componentes de mensajeria de nivel inferior. New Era of Networks (NEON), Mercator (antes TSI), Vitria, SeeBeyond, BEA y Candle estin comprometidos en lo que se ha convertido en un mercado muy concurrido. La mayoria de las organizaciones son conscientes en la actualidad del enorme valor de Enterprise Applicaction Integration (EAI) y, en conjuncion con el crecimiento exponencial de empresas electrbnicas, esto ha ampliado la importancia fundamental de la tecnologia de mensajeria mis alli de las fronteras de la empresa y de la Web. Enterprise Application Integration (EAI) es la pdctica de conectar aplicaciones distribuidas dispares. Arrastradas por este crecimiento, muchas compafiias han carnbiado a tecnologias de base Java. Aunque sus productos mantienen a menudo sus nucleos de base C o C + Java ha sido adoptado como el lenguaje preferido para crear herramientas de mensajeria y librerias.

+,

Como parte del Java Community Process UCP), y en colaboraci6n con la vanguardia de vendedores de mensajeria de empresa, Sun se propuso proporcionar un API de mensaje de base Java que pudiera envolver la semintica genkrica de entrega de mensajes ofrecida por 10s proveedores M O M establecidos. El resultado fue el API de Servicio de Mensajeria de Java. Publicado en Agosto de 1998 por primera vez, proporciona un sistema que capacita el desarrollo en Java de aplicaciones portitiles basadas en mensajes. Estas aplicaciones, que son distribuidas por lo general, se comunican asincr6nicamente a travCs de mensajes.

Muchas compa?iias desempenan un papel en el futuro desarrollo del API JMS. Puede encontrar una lista actualizada de JMS bajo licencia en http:lljava.sun.comlproductsljmsllicensees.html. Una lista similar de vendedores JMS (sin licmcia) puede encontrarse en http:lljava.sun.comlproductsl
jmslnonlicensedvendors. html.

Servicio de Mensajes Java (JMS)


El Servicio de Mensajes Java es u n API Java que proporciona interfaces a las aplicaciones para que creen, reciban y lean mensajes utilizando cualquier implementacidn que se adapte a1 API. Esto es posible puesto que la gesti6n y el empaquetamiento de nivel inferior de 10s mensajes dependen de la implenlentaci6n, que restringe la interoperabilidad exclusivamente a las implementaciones cooperantes. El API JMS (como 10s API J N D I y JDBC) prescribe s61o interfaces. Queda para 10s terceros la provisi6n de implementaciones reales. La intenci6n subyacente a este enfoque era proporcionar un API minimo, que maximizara la portabilidad per0 todavia ofreciera un poderoso conjunto de funciones de mensajeria. U n enfoque asi reduce la dependencia respecto de una implementaci6n concreta y reduce la curva de agrendizaje necesario para proporcionar funcionalidad bisica.

Capitulo 19
Corno consecuencia directa, este enfoque del disefio del API JMS tiende a aurnentar la cornpetencia entre wendedores para ofrecer apoyo, reajustabilidud y rendirniento en lugar de APZ o funciones; una ventuja para todos.
JMS permite un sistema de comunicaci6n dkbilmente acoplado que es asincrono y fiable:

O Asincrono significa que el receptor no tiene que solicitar activamente un mensaje para recibirlos.
Esto es comparable a c6mo no vamos cada maAana a Seur para comprobar si tenemos algfn envio; en cambio, s61o proporcionamos una direcci6n para la entrega.

O Fiable significa que se nos puede garantizar una, y s d o una, entrega de mensajes; esto es esencial
en sistemas modernos. Si un sistema de mensajeria n o fiable se utilizara para realizar 10s pedidos semanales de compras y la conexi6n de Internet se perdiera durante el pedido, asumiriamos que el pedido no se lleva a cabo. Si realizamos el pedido por segunda vez, podriamos perfectamente recibir un pedido doble. Los sistemas de mensajeria pueden dividirse en dos dominios generales: punto-a-punto y publicarl suscribir. Aunque JMS apoya ambos dominios, un proveedor independiente (es decir, uno que no forma parte de un servidor de aplicaci6n JZEE) s610 tiene que implementar uno de ellos. Sin embargo, la mayoria de 10s proveedores apoyari ambos dominios. U n proveedor JZEE debe implementar ambos dominios para cumplir la especificaci6n J2EE.

Punto-a-punto (PTP) define un dominio de mensaje, basado fundamentalmente en colas.

t a coha son almacenes persistentes (pero, en ocasiones, en memoria) l o ~ l i z a d o s en el destino JMS.

Las colas obedecen a la regla F I F O (First In First Out); es decir, 10s mensajes abandonan la cola en el mismo orden en que han sido enviados. Todos 10s mensajes son enviados a una cola especifica, donde permanecen hasta que expiran o hasta que son consumidos por el receptor. El emisor no necesita tener conocimiento del receptor y el receptor n o necesita saber d6nde se ha producido el mensaje. Sin embargo, debido a la naturaleza precisa de la mensajeria punto-a-punto, es com6n que ambas partes sean conocidas en la aplicaci6n. Esto significa que la cola de mensajes siempre es el punto com6n de intercambio.

La siguiente figura ilustra 10s procesos implicados en el envio de mensajes entre el productor y el consumidor a traves de la cola de mensajes:

Mensaje
I

1
I
--

Men!mje
-.

/
Cola

+ F m m m u

Conswrr;dor

Aqui hay tres partes: el productor, la cola y el consumidor. Cada una de ellas puede residir en un equipo diferente o en el mismo equipo. La cola se ejecuta como parte del JMS y podria implementarse en Java, C , C + o cualquier otro lenguaje.

JMS y beans controlados por mensaje


Hay tres puntos importantes que debemos tener en cuenta a la hora de pensar en mensajeria punto-apunto en JMS:
0

Cada mensaje tiene un unico consumidor. Puede haber varios consumidores pertenecientes a una cola per0 uno y s61o un consumidor consumiri un mensaje individual. Varios productores pueden enviar mensajes a la misma cola y no hay ningun motivo por el que un consumidor no pueda tambikn consumir mensajes procedentes de varias colas. Enviar y recibir mensajes n o depende del tiempo. U n productor puede enviar un mensaje en cualquier momento; el mensaje en cola puede ser consumido en cualquier momento posterior antes de que expire. Lo Gnico que debe estar ejecutindose, para que ambos lados funcionen, es la cola de mensajes (que puede ser un proceso permanente). N o es necesario que 10s clientes JMS (el productor y el consumidor) se ejecuten a1 mismo tiempo y el consumidor no tiene que haberse registrado con una cola antes de que el mensaje sea enviado. Sin embargo, tanto productor como consumidor, deben estar de acuerdo en una cola c o m h .

El consumidor debe reconocer la r e c e p c i h del mensaje. Esto puede ocultarse a la aplicacion y realizarse automiticamente, manualmente despuis del procesamiento o como parte de una transacci6n. Una vez que el consumidor ha reconocido la recepcibn, el mensaje es eliminado de la cola.

Dada una cola de mensajes, podemos utilizar,a varios consumidores (en diferentes equipos, si asi lo deseamos) para recoger mensajes de la cola. Esta es una sencilla forma de equilibrio de carga, no a1 nivel JMS sino utilizando JMS para equilibrar la carga en el nivel de la aplicaci6n. Cada nuevo mensaje seri consumido por uno (y solamente uno) de 10s consumidores. Si ese consumidor esti ocupado procesando un mensaje, otro consumidor tomari el siguiente mensaje, repartiendo la carga entre 10s equipos. Los mensajes punto-a-punto se utilizan habitualmente cuando todos y cada uno de 10s mensajes tienen como resultado una acci6n que debe ser procesada una vez y solamente una vez. Ejemplos incluyen aplicaciones financieras, sistemas de pedidos y 6rdenes de control de transmisi6n de aplicaciones (por ejemplo, enviar un comando de "cerrar").

U n dominio publicar/suscribir (pub/sub) puede tener multiples recipientes por mensaje. Esto no es posible en un dominio punto-a-punto y ksta es la principal diferencia entre 10s dos dominios. N o existen colas en el dominio pub/sub; en su lugar, 10s mensajes son publicados y enviados a apartados. Los apartados son similares a las colas except0 que multiples consumidores pueden compartir un Gnico mensaje. Al igual que las colas, 10s apartados son FIFO una vez que el consumidor se ha suscrito, igual que en el dominio punto-a-punto, varios productores pueden publicar mensajes para un unico apartado. Los apartados retienen 10s mensajes durante tanto tiempo como tardan en distribuirlos a 10s consumidores. Los suscriptores de un dominio pub/sub son habitualmente, per0 no estrictamente, an6nimos. Es decir, son desconocidos para el que publica:

Capitulo 19
4 .

Mensaje

Los puntos importantes a tener en cuenta sobre el dominio publicar/suscribir son 10s siguientes: Cada mensaje puede tener multiples (cero, uno o mis) consumidores. Los suscriptores s61o pueden consumir mensajes publicados despuks de su suscripci6n. Esta dependencia del tiempo es lo que diferencia a1 dominio de 10s mensajes enviados punto-a-punto. Si en el caso anterior, por ejemplo, el productor p u b h a un mensaje nuevo, ambos consumidores, 1 y 2, (suponiendo que se hayan suscrito) recibiran el mensaje. Sin embargo, si el consumidor 3 se incorpora despuks y se suscribe a1 mismo apartado, no recibid el mensaje.

O Los suscriptores deben, en general, permanecer activos para consurnir mensajes. (La excepcion a esta regla se da con las suscripciones duraderas, que proporcionan la flexibilidad asincrona de las colas mientras retienen a m~iltiples consumidores. Trataremos este punto con m&sdetenimiento mas adelante.)
U n escenario tipico para utilizar un dominio publicar/suscribir es un sistema en el que el servidor publica datos para suscribir a clientes. Esto significa que el servidor puede publicar informaci6n para apartados a 10s que pueden suscribirse opcionalmente 10s clientes. La aplicaci6n servidor no tiene que gestionar quk clientes desean qu6 informacihn; el JMS se encarga de todo. Esencialmente, es un mecanismo de manejo de eventos distribuidos al que nos suscribimos en lugar de afiadirnos con10 oyentes de eventos.

La arquitectura JMS
Existen seis bloques de construcci6n principales en la arquitectura JMS. Son utilizados uno a uno para construir la aplicaci6n JMS:

rn Objetos administrados
Objetos que se mantienen normalmente fuera del programa, a menudo a travis de alglin tip0 de herramienta de administraci6n. Son por lo general objetos de factoria exclusivos de la implementaci6n JMS. Si la implementaci6n del API JMS es pane de una implementaci6n J2EE (como ocurre con las especificaciones JZEE), la gesti6n se realiza utilizando JNDI. La Implementaci6n de Referencia J2EE 1.3 de Sun proporciona una herramienta de administraci6n ( jZeeadmin) que puede utilizarse para administrar JMS.
0 Conexiones

U n tkrmino generic0 para las conexiones al servidor del proveedor JMS, con frecuencia una conexi6n de socket entre el cliente y el servidor JMS. Las conexiones son obtenidas desde una

JMS y beans controlados por mensaje


factoria de conexiones y pueden utilizarse para crear una o rnis sesiones. Hay dos tipos de conexiones, la ~ u e u e c o n n e cito n y la ~ o p i c ~ o n n e c t i oCorno n. sucede con todas las clases JMS, estas conexiones son en realidad interfaces. Una vez se ha realizado una conexibn, se inicia utilizando el rnktodo s t a r t ( ) . El servicio t a r n b i h puede ser interrurnpido o reiniciado sin perder la conexi6n. Interrurnpir una conexi6n significa que 10s rnensajes n o pueden ser consurnidos per0 n o pone fin a la capacidad de rnanejar 10s mensajes producidos. Las conexiones utilizan recursos de sisterna, por lo que deben cerrarse despuCs de su uso. N o existen normalmente rnuchos rnotivos para tener rnis de una conexi6n; sin embargo, en ciertos casos, puede que se requiera una segunda conexibn. Por ejernplo, las pasarelas pueden realizar una conexidn a un servidor JMS para consurnir rnensajes y realizar una segunda conexi6n para producir rnensajes para un servidor JMS diferente, proporcionando un vinculo entre 10s dos.
0

Sesiones Proporcionan el context0 transaccional para agrupar un conjunto de rnensajes. El objeto s e s s i o n se utiliza para crear 10s productores de rnensaje, 10s consurnidores y 10s rnisrnos rnensajes. Igual que sucede con las conexiones, hay dos tipos de sesiones: T o p i c s e s s i o n y Queuesession. Productores de mensaje Los productores de rnensaje son creados por la sesi6n. Envian rnensajes a el/los destino/s. Una vez rnis, existen dos tipos de: Q u e u e s e n d e r para punto-a-punto y T o p i c S e n d e r para publicar/ suscribir. Estos ernisores tienen, cada uno de ellos, un rnitodo ernisor: s e n d ( ) en el caso de QueueSendery p u b l i s h ( ) e n e l c a s o d e ~ o ~ i c s e n d e r . Se encuentran a1 otro extrerno del apartado/cola JMS respecto de 10s productores y reciben 10s rnensajes enviados a un destino. Una vez rnis, hay dos versiones: Q u e u e R e c e i v e r y T o p i c s u b s c r i b e r . Los consurnidores de rnensaje ernpiezan a recibir rnensajes tan pronto corno se inicia la conexi6n (despuks de haber invocado s t a r t ( ) ). Los rnensajes pueden ser consurnidos sincronicarnente utilizando r e c e i v e ( ) o asincr6nicarnente utilizando el rnktodo o m e s s a g e ( ) de~essage~ te in s e r . Los rnensajes t a r n b i h pueden ser consurnidos selectivarnente utilizando s e l e c t o r e s dernensaje.

o Consumidores de mensaje

0 Mensajes Estos envuelven a 10s datos, enviados desde 10s productores, para ser recibidos por 10s consurnidores. Los mensajes estin cornpuestos por tres partes: la cabecera contiene detalles corno destino, responder-a destino, caducidad, prioridad y estarnpilla de tiernpo; las propiedades son una extensi6n de la cabecera y contiene carnpos de cabecera opcionales asi corno una serie de pares de valor nornbre especificos de la aplicaci6n, accesibles desde el o b j e t o ~ e s s a g ey ; el cuerpo del mensaje, que puede ser de varios subtipos:
0

B y t e s M e s s a g e . Bytes primigenios, utilizados con mayor frecuencia para cornunicar c o n , consurnidores y productores de mensaje distintos de Java.

0 MapMessage. Similar a un HashMap de pares valor-clave. El clave es un objeto S t r i n g y el valor puede ser cualquier objeto Java.

O M e s s a g e . U n cuerpo vacio, s61o la cabecera y las propiedades.


0 Ob j e c t M e s s a g e . Objetos Java serializables.

O s t r e a m e s s a g e . Una corriente secuencial de prirnitivas Java.


0 T e x t M e s s a g e . U n rnensaje s t r i n g (a rnenudo utilizado para enviar rnensajes XML).

Capitulo 19
Los mensajes son creados a partir del objeto Session y el tipo de mensaje se define en el metodo de creacibn. Esta figura resume las dependencias y relaciones entre 10s bloques de construccibn JMS:

Crea

d 2 :ctoria Conex~ones

crea

t Conex16n

Crea

Crea

Crea

btiene de ___,

Ejemplo de cola punto-a-punto


H a llegado el rnornento de que exarninemos algo de cbdigo. Prirnero, varnos a analizar rnensajes punto-apunto, creando un rnensaje y enviindolo despuis. Entonces podernos reutilizar gran parte del cbdigo, realizando s6lo algunos carnbios de mod0 que podamos recibir el mensaje que hernos enviado.

La siguiente c l a s e , ~ r o x ~ u e u e ~ e n d sirnplemente er, sigue 10s pasos que hernos estudiado para enviar un simple rnensaje. Adicionalmente, aiiadiremos un s t r i n g p r o p e r t y al rnensaje para conseguir que el mensaje sea rnis real:
import javax. jms. * ; import javax.naming.*; public class WroxQueueSender { public static void rnain(Strinq[] args) { Queue queue = null; Q u e ~ e C o n n e c t i o n F a c t o r y queueConnectionFactory QueueConnection queueConnection = null;

null;

Utilizamos objetos adrninistrados para obtener la factoria de conexiones. En este caso, estarnos utilizando

JNDI para obtener una referencia a Q u e u e C o n n e c t i o n F a c t o r yde JMS. La cola rnisrna tarnbiin se
obtiene del servicio de nornbrado; por ello, si no existe la cola refundida, se genera una excepci6n:
try i

JMS y beans controlados por mensaje


Context j ndicontext = new Initialcontext ( ) ; queueConnectionFactory =(QueueConnectionFactory)jndiCor1text~10okup( "QueueConnectionFactory"); queue = (Queue) j ridicontext. lookup ("WroxOrders" ) ; catch (NamingException nEx) [ System.out.println(nEx.toString()t"\r~Does the queue exist?"); ; System. exit ( 1 )

El codigo que hemos visto hasta el momento seri virtualmente idintico para productor y consumidor. Lo Gnico que hemos hecho ha sido solicitar a1 servicio de nombrado Q u e u e C o n n e c t i o n F a c t o r y . (Una herramienta de administraci6n JMS configurari normalmente esto.)

A continuaci6n, u t i ~ i z a m o s ~ u e u e ~ o n n e c t i o n ~ a c paracrear t o r y u n a Q u e u e C o n n e c t i o n , que se utiliza entonces para crear la sesibn. El primer parimetro nos permite activar el mod0 transaction; si esti
configurado en t r u e , mitodos s e s s i o n como c o m m i t ( ) y r o l l b a c k ( ) pueden utilizarse para agrupar mensajes en una transacci6n. El segundo parimetro, S e s s i o n . AUTO-ACKNOWLEDGE es irrelevante para el productor per0 asumiri importancia cuando creemos un consumidor:
- -

try t queueConnection = queueConnectionFactory. createQueueCor~nectior~ ( ) ; QueueSession queuesession = queueConnection.createQueueSession( false, Session.AUT0-ACKNOWLEDGE);

A partir de este punto, existen marcadas diferencias entre las clases del productor y del consumidor. Ahora utilizamos Q u e u e S e s s i o n para crear el productor, Q u e u e S e n d e r y el mismo mensaje (en este caso u n T e x t M e s s a g e ) :
QueueSender queuesender = queueSession.createSender(queue); TextMessage message = q u e u e S e s s i o r ~ . c r e a t e T e x t M e s s a g e ( ) ;

El o b j e t o ~ e s s a g e (0, en este caso, el objeto ~ e x t M e s s a g e tiene ) una serie de metodos set y get. Podemos ignorar la mayoria de estos mitodos en este ejemplo per0 utilizamos dos de ellos para demostrar 10s principios bisicos:
message.setText ("Please send me the new J2EE book on my account"); message. setStringProperty ("Clientt', "Rachel Davies");

Invocamos entonces el metodo s e n d ( ) para enviar el mensaje a la c o l a que hemos definido:


queuesender. send (message) ; System.out .println ("Your book has been ordered" ) ;

Capturamos cualquier excepci6n que pudieraejecutarse:


1 catch
(JMSException jmsEx) { System.out.prir~t("Something went wrong with your book order, " 1 ; System.out .println("please try again...") ; System.out .println ("Exception: " t jmsEx. tostring ( ) ) ;

Finalmente, cerramos Q u e u e c o n n e c t i o n para liberar 10s recursos:


)

finally { if (queueConnection ! = null ) [ try t queueConnection. close ( ) ; ) catch (Exception any) { }


1

Capitulo 19

Ahora, para conseguir que este cbdigo funcione, es necesario realizar dos operaciones. El orden en que las re.dicemos dependera de la implementation JMS que esternos utilizando. Necesitamos:
U Crear la cola, que en nuestro ejemplo se llama w r o x ~ r d e r s

O Iniciar 10s servicios JMS

Daremos estos pnsos utilizando la Implementaci6n de Referencia J2EE (version 1.3). Sun proporciona j Z e e a d m i n (que e s t i bien documentada en el documento una herramienta de,administraci6n llan~ada adiunto lavadoc). Esta es una herramienta de linea de cornando que puede utilizarse para afiadir, eliminar o enumerar drivers y destinos y factorias JMS. Para ariadir la cola JMS W r o x O r d e r s para su uso en el ejemplo anterior, ejecute el siguiente comando:

.:~~,~,-lni -a !1 -~ 3~-ijmzDe t .i ~r a t i r r,

E!r.~>:,Or';'rrs s - j r ~ e u e

Par3 cornprobar que ha sido creada, utilice la opcibn de c o r n a n d o - l i s t j m s ~ e s t i n a t i o n ejecutandoel siguiente comando:
i:eei-inzir,

- l i s t i n : - - P e : = t i n d t iL;rt

V e ~ la i siguiente salida, confirmando que nuestra cola ha sido creada:

Ahora estnmos preparados para inicinr el servidor J2EE. Para poder seguir lo que e s t i pasando, debemos utilizar In opcion - v e r b o s e . Ejecute el siguiente comando:

iF

-.

' r t .

5;-

Debe observar que W o r x O r d e r s e s t i i n c l u i d o h r n o destino JMS:

JMS y beans controlados por mensaje


En este punto, y ; ~ estamos casi preparados para compilar y ejecutar W r o x ~ e n d e r Hay . un paso niis que debemos dar antes d e ello, que es proveer al servidor JZEE de algunos parinietros antes de que inicie el JMS. Estos parlnietros pueden ser configurados en nuestro programa pero, para rnantener el c6digo tan portitil con10 sea posible, deben ser configurados en el period0 de ejecuci6n. Esisten algunns forrnas de hacerlo pero la rnis sencilla consiste en configurar la propiedad j m s . p r o p e r t i e s en la linea de comando. El archivo d e propiedades por defect0 para In Implementaci6n de Referencia JZEE puede encontrarloen%J ~ E E - H O M E :\ c o n f i g \ j m s - c l i e n t . p r o p e r t i e s ycontiene:

Ahora, c o ~ n p i l e ~ r o x ~ u e u e ~ e (n nd oe olvide r i n c h j 2ee. j a r en la ruta de clase):

Ejecute entonces el progrania, configurando la propiedad j m s . p r o p e r t i e s en la linea d e coniando:

Debt ver nlgo asi:

Asi, el libro ha sido solicitado pero iddndc e s t i cl mensaie? Nuestro mensaje se ha perdido. En este punto, podenios detcner J2EE mientras nprcndenios ~61110 recibir un rnensaje.

Consumir un mensaje sincronicamente Necesit~nios importar j a v a . u t il . D a t e pero gran parte del c6digo para n u e s t r o Q u e u e R e c e i v e r seri
el misnio que p a r a W r o x Q u e u e S e n d e r :

Capitulo 19
Context jndlContext = new InitialContext ( ) ; queueConnectior~Factory = ( Q u e u e C o n r ~ e c t i o r , F a c t o r y j)ndiContext . lookup (
"QueueCor~nectionFactory");
)

yueue = ( Q u e u e ) jndiContext. lookup ("WroxOrders"); catch (NarningException nEx) { Systern.out .println (nEx.tostrir~g ( ) ti'\nDoes the queue exist?") ; System.exit(1);

I Solamente necesitamos analizar la secci6n t r y que difiere de la clase emisor. De nuevo utilizaremos
QueueConnectionFactoryparacrearQueueConnection. QueueConnectionseutilizaentonces

para crear u n a Q u e u e S e s s i o n . Esta vez, S e s s i o n .AUTO-ACKNOWLEDGE es utilizada para configurar Q u e u e s e s s i o n para enviar automiticamente acuses de mensajes consumidos:
try i queueConnection = queueConnectionFactory. createQueueConectior~ ( ) ; Queuesession queuesession = q u e u e C o r ~ n e c t i o n . c r e a t e Q u e u e S e s s i o n ( false, Session.AUT0 ACKNOWLEDGE); QueueReceiver queueReceiver = q u e u e S e s s i o n . c r e a t e R e c e i v e r ( q u e u e ) ; queueConnection.start ( ) ;

Para consumir o recibir el mensaje, lo dnico que tenemos que hacer es invocar el metodo r e c e i v e ( ) , que esti sobrecargado. La versi6n sin parimetros se bloquea hasta que hay un mensaje disponible. El otro metodo, r e c e i v e ( l o n g ), toma un argument0 de plazo de tiempo en milisegundos y devuelve n u l l si el plazo de tiempo expira o si la conexi6n a a1 cola no se ha iniciado; esto es lo que utilizaremos. (Tambih hay un m k t o d o r e c e i v e ~ o ~ a( i) t.) Si se recibe un mensaje, leemos las propiedades JMSTimestamp y C l i e n t , que deben haber sido configuradas por el productor. JMSTimes t a m p es un campo predefinido en la cabecera del mensaje y es configurada por el emisor.
TextMessaqe message = (TextMessaqe) queueReceiver.receive(1); if (messaqe ! = null) { Date timestamp = new D a t e ( m e s s a q e . q e t J M S T i m e s t a m p ( ) ) ; Strinq client = m e s s a q e . q e t S t r i n q P r o p e r t y ( " C l i e r ~ t " ) ; System.out.println("New order from "+client+" at "+timestamp); System.out.println("-> "trnessaqe.qetText0); 1 else { System.out. println ("No new orders.. . " ) ;

catch (JMSException jmsEx) I Systern.out .print ("Something went wrong with your book order, System.out .println ("please try again...") ; System.out .println ("Exception: " t jmsEx.toString( ) ) ; finally { / if (queueConnection ! = null) { try I queueConnection.close ( ) ; . I catch (Exception arty) { I

" ) ;

Siga estos pasos para ejecutar el ejemplo. Ejecute el siguiente comando para compilar WroxQueueReceiver:
javac -classpath .;%JZEE HOME%\iib\j2ee.jar W r o x Q ~ . l e u e R e c e i v e r . j a v a
-

Reinicie el servidor J2EE:

JMS v beans controlados por mensaie


L++

-..erk

-,>

Entoncea, ejecute ~ r o x ~ u e u e ~ e c e ~ incluyendo ver, el mlsnlo archivo de propiedades anterior:

Aunque hemos detenido el servidor JZEE, el mensaje todavia estaba disponible (incluso hubiera estado ahi si se hubiera arrancado su ordenador de nuevo). Esto demuestra que la cola de destino JZEE es persistente. Esto no es siempre asi; el productor de nuestro ejemplo ha utilizado 10s parinietros por defect0 al enviar el mensaje. Para ser portitil, estos padmetros en realidad necesitan ser definidos esplicitamente en la versi6n mis eshaustiva del metodo s e n d ( ) . Si sustituimos:

E n w r o x Q u e u e S e n d e r por:
q u e u e S e n d e r . s e n d (messaqe, DeliveryMode.PERSISTENT, Message. D E F A U L T P R I O R I T Y , 60L1000L) ; . .

Se enviara el mismo nlensaje pero s d o durari un minuto.

Consumir un mensaje asincronicamente


Hasta ahora hemos enviado (o producido) un mensaje y despuks lo hemos recibido (o consumido). Hemos tratado 10s rnodos en 10s que podemos utilizar el metodo r e c e i v e ( ) per0 necesitariamos sondear (en bucle) continuamente, para consumir mensajes a medida que vayan Ilegando. En un entorno como JFC, 10s eventos asincronos como movimientos de r a t h o clic de teclado son manejados por oyentes. Lo mismo sucede si queremos recibir mensajes asincr6nicamente; es necesario que utilicemos un M e s s a g e L i s t e n e r . Utilizar u n M e s s a g e L i s t e n e r significa que laaplicaci6n puedecontinuar con otras tareas mientras dejamos al oyente que procese 10s mensajes entrantes. Creemos una nueva clase W r o x Q u e u e R e c e i v e r A que pueda consumir mensajes asincronicamente. Gran parte del c6digo seri igual paraWroxQueueReceiver:
impcrt import
j ava.util.Date;
j a v a x . j m s . ';

Capitulo 19
import j avax. naming.-;

p u b l i c c l a s s WroxQueueRecei~/erA { public s t a t i c void main(Strir~g[largs) { Queue qlleue = n u l l ; QueueCor~riectionFactory queutConr~ectionFactor~ = . null; QueueConnection queueConnection = n u l l ; try i C o n t e x t j n d i C o n t e z t = new I n i t i a l C , > r ~ t e x ( t) ; q u ? ~ ~ e C o r ~ r ~ e c t i o r ~ F a c= t, (QueueConnectionFactory) ?ry j ndi C o r ~ t e x. tlookup ( " Q u e u e C o n n e c t i a r ~ F a c t o r y " ); queue = (Queue) j ndiCaritext. lookup ( "WroxOrdersW ) ; } c a t c h (NamingException nEx) { S y s t e m . o u t . p r i n t l n ( r ~ E xt .t j S t r i r ~ g (t ) l'\r~Does t h e queue e x i s t ? " ) ; S y s t e m . e x i t (1);
I
I

try q u e u e C o r , r , e c t i o r , = q u e u e C o n n e c t i a r ~ F a c t o r yc . r e a t e Q u e u e C o r i r ~ e c tr i~ ( ) ; Q u e u e S e s s i o n q u e u e S e s s i , - n = q u e u e C o n r ~ e c t i c ? rc ~r. e a t e Q u e u e S e s s i o n i false, QueueReceiver q11eueReceiver


=

Session.AUT0-ACKNOWLEDGE); queueSession.createReceiver(que);

Hasta el rnornento todo es igual, per0 ahora necesitarnos configurar e l M e s s a g e L i s t e n e r antes de iniciar la Q u e u e c o n n e c t i o n . El rnotivo es que tan pronto corno se inicie la Q u e u e c o n n e c t i o n , se invocari e l ~ essa g e L i s t e n e r en cualquier rnornento:
WroxListener wroxListener
=

new W r o x L i s t e n e r

( ) ;

queueReceiver.setMessageLister~e~-(wroxListener);
queueC<:>nnection. start ( ) ;

Ahora podernos continuar y hacer lo que tengarnos que hacer en la aplicaci6n sin preocuparnos por 10s rnensajes. Por ejernplo, podriarnos cornenzar rnostrando algunas estadisticas de rnensaje, procesando 10s rnensajes per0 asurniendo q u e M e s s a g e L i s t e n e r 10s esti escribiendo en una base de datos o clasificando 10s rnensajes y volviendo a enviarlos a otras colas o apartados. E l ~ e s s a ~ e ~ i s t epodria n e r ser cierta forrna de "alrnackn seguro", un tkrrnino utilizado a rnenudo en sisternas M O M que requieren que 10s rnensajes sean alrnacenados en disco. Los alrnacenes seguros se utilizan con mayor frecuencia en aplicaciones financieras puesto que, una vez en el disco, 10s rnensajes estin a salvo de fallos MOM. O t r o uso frecuente consiste en insertar en rnensaje en una base de datos para una posterior recuperaci6n. N o varnos a realizar ninguna operaci6n tan cornplicada corno Csta, sino que sirnplernente varnos a esperar alrededor de un rninuto para ver si hay algun rnensaje rnis:
System.out . p r i n t l n ("Waiting 1 minute f o r messages.. .") ; f o r i i n t 1 = 6 0 ; i > 0 ; i-) [ S y s t e m . ~ u .t p r i n t ( " C o u n t d o w n . . . " t l t " \ r " ) ; Thread.sleep(1000L);

1
]

I
System.out.println("JMSException: " + j m s E x . t o S t r i n g catch(1nterruptedException i n t E x ) {
System.out . p r i n t l n ( " I n t e r r u p t i o n : finally { i f (queueConnection != n u l l ) { try { ,queueConnection.c l o s e ( ) ; ] catch (Exception any) [ ]
I

catch

(JMSException jmsEx)

. . -

( ) );

"

intEx. tostring ( ) ) ;

JMS y beans controlados por mensaje

Es necesario que capturemos cualquier instancia de excepci6n I n t e r r u p t e d E x c e p t i o n que podria generarse debido a1 uso d e ~ h r e a d s. l e e p ( ) . Analicemos ahora n u e s t r a c l a s e ~ e s s a g e ~ i s t e n e~ r .s t a es la principal parte de control de mensajes de la aplicaci6n. En este ejemplo, n u e s t r a M e s s a g e L i s t e n e r se Ilamawr o x ~ itse n e r . Implements la i n t e r f a z ~ e s a g e L i s t e n e r , que requiere que proporcionemos una implementaci6n para el metodo o w e s s a g e ( ) :
import j ava . u t i l .Date; import j avax. j ms. * ; public class WroxListener implements MessageListener
{

public void onMessage(Message message) { try I if (message instanceof TextMessage ) { TextMessage textMessage = (TextMessage) message; Date timestamp = new Date(textMessage.getJMSTimestamp()) ; String client = textMessage.getStrir~gProperty("Clier~t"); Systern.out .prir~tln ("\r1New 3rder from "tclientt" at "+timestamp); System. out .println "+textMessage.getText ( ) ) ;
('I->

Podemos t a m b i h procesar otros tipos de mensaje si 10s tenemos:


]

else if (message instanceof ObjectMessage) { Obj ectMessage obj ectMessage = ( O b jectMessage) message;

I
J

catch (JMSException j m s E x ) { System.out .println ("JMSExceptior1 in onMessage ( ) : " t jmsEx.toString()) ; catch(Excepticn e ) { System.out .println ("Exception: " + e. tostring ( ) ) ;

I
Es asi de sencillo. Este metodo es invocado ahora cada vez que llega un mensaje a1 destino Q u e u e . Ejecute el siguiente comando para c o r n p i ~ a r ~ r o x Q u e u e ~ e c rA eiv ye WroxListener:
j a v a c -classpath . ; % J 2 E E p H 0 M E % \ l i b \ j 2 e e . j a r WroxQueueRe WroxListerler. j ava

Recuerde iniciar el senidor J2EE y ejecute entonces el siguiente comando para ejecutar el ejemplo (recordando pasar el archivo de propiedades en la linea de comando Java):
j ava -Djrns .properties=% J2EE HOME%\config\ jrns client .properties - c p . ;% J2EE HOME%\lib\j 2eeTj ar; W r o x Q u e u e ~ e c e i v e r A
-

Mientras se ejecuta, debe ejecutar varias veces W r o x Q u e u e S e n d e r para enviar algunos mensajes nuevos. Debe ver algo asi:

Capitulo 1 9

Puede ver en esta captura d e pantalla q u e W r o x Q u e u e R e c e i v e r A ha recibido tres mensajes.


Es conveniente destacar la interfaz E x p c e t i o n L i s t e n e r . Puede utilizarse para construir controladores de escepciones. Puesto que, esencialmente, hemos desacoplxlo el receptor en el ejemplo anterior, n o tenemos forma alguna de procesar exccpciones; podemos conseguirlo implementando E x c e p t i o n L i s t e n e r y proporcionando una iniplementacion para el m6todo o n E x c e p t i o n ( J M S E x c e p t i o n ) . U n sencillo ejemplo seria i n v o c a r p r i n t s t a c k ~ r a c (e) en el parimetro de excepci61-1.

Ejemplo de apartado publicar/suscribir


Un prograrna que utilizn apartados y publicar/suscribir es tan sencillo d e implementar c o m o un programa que utiliza colas y punto-a-punto. Sin embargo, hay m i s funciones disponibles en este dominio. Para crenr un programa que utiliza apartados y publicar/suscribir, podemos tomar literalmente el c6digo ur s t i t u i r " q u e u e n p o r " t o p i c " , " s e n d e r " por " p u b l i s h e r " y a n t e r i o r ~ r o x ~ u e u e ~ e nydse " s e n d " por " p u b l i s h " , renombrar el archivo y compilarlo. Sin embargo, para hacerlo un poco mas interesante, afiadiremos tres mensajes en lugar de afiadir solo uno. Nuestra aplicaci6n anunciard sus nuevos libros a 10s suscriptores; por ejernplo, a compradores al p o r mayor o individuales que hayan manifestado interis por determinados tipos de libros. Supondremos que 10s siguientes libros acaban de publicarse:
2 Programaci6n Profesional J2EE Java Server
7

Referencia para Programadores Java XML ASr'.NET I'rofesional

Cadn libro tendri propiedades como alcmce del terna, lenguajes, autores, nlimero ISBN y precio pero solo algunas de estas propiedades han sido implementadas en nuestro c6digo de ejemplo. El codigo para esta c ~ a s e , ~ r o x ~ o p ~ c ~ u b les i smuy her similaral , de~rox~ueue~ender:

JMS v beans controlados por mensaie


Topic topic = null; TopicConnectionFactory topicConnectlonFactory TopicConnection topicCor~nection = null;

null;

try 1 Corltext jr~dicorltext = new InitialContext ( ) ; topicCor~nectionFactory = ( T o p i c C o n n e c t i o n F a c t o r y ) j ridicontext.lookup ( " T o p i c C o r ~ n e c t i o n F a c t o r y " ) ; topic = (Topic) j ndicontext. lookup ("WroxPub1icatior~s") ; ) catch (NamingException nEx) { System.out .println (riEx.tostring ( ) +''\riDoes the topic exist?") ; System.exit(1);

I
try 1 topicConnection = topicConnectior~Factory.createTopicCor~nection(); TopicSession topicSession = topicConnectiori.createTopicSession( false, Session .AUTO ACKNOWLEDGE) ; Topicpublisher topicPublisher = topicSession.createPublisher(topic); TextMessage messagel TextMessage message2 TextMessage message3
= =

topicSession.createTextMessage~); topicSession.createTextMessage(); topicSession.createTextMessage~);

rrlessagel.setText ("The new Pro JZEE book 1 s now our") : messagel. setstringproperty ("MetaData","Java, J2EE,EJB, JMS") ; messagel. setstringproperty ("Languages","Eriglish") ; message2.setText ("The new Java XML book is now out"); message2 .setstringproperty ("MetaData","Java,XML"); message2. setstringproperty ("Languages","English") ; message3.setText ("The new Pro ASP.NET book is out"); message3. setstringproperty ( " M e t a D a t a " , " M i c r o s o t ,. N E T , A S P W ) ; message3.setStringProperty ("Languages","English, Deutsche,Alsacien") ;

Los cuatro parirnetros del siguiente metodo p u b l i s h ( ) son el rnensaje, el mod0 de entrega (PERSISTENT o NON-PERS ISTENT), la prioridad y, finalrnente, la duraci6n de la vida del rnensaje (en milisegundos):
topicPublisher.publish(messagel, DeliveryMode.PERSISTENT, Message.DEFAULT PRIORITY, 7*24*3600*1000L); topicPublisher.publish(message2, DeliveryMode.PERSISTENT, Message. DEFAULT PRIORITY, 7*24*3600t1000L); topicPublisher.publish(message3, DeliveryMode.PERSISTENT, Message.DEFAULT PRIORITY, 365*24*3600*1000L);
}

System.out.println("3 books have been published today."); catch (JMSException jmsEx) { System.out.println("Sorry, something went wrong with publishing..."); System.out .println ("Exceptiori: " + jmsEx. tostring ( ) ) ; ] finally I if (topicConnection ! = null) { try i topicCor~nectlon. close ( ) ; ) catch (JMSException any) { ) 1

I I

Capitulo 19
Necesitanios crear el apartado en J2EE, utilizando el siguiente comando:
j: ? ; a J m i n
-a8:i.iir~i,=neetination L.lrc:iE'~~h Il c a t i i.ri.=

r;:,(.,ii

Compile a h o r a ~ r o x ~ o ~ i c ~ u b l i ejecutando sher el siguiente comando:


iava,:
-c'ld."5p3t.tl

.; V . J ? E E - H O M E % \ L i h \ i i i i . j d r

P ! ~ r ~ ~ T ~ ? ~ i c P u h lis av tV ~3 e ~ - .

Finalmente, inicie el servidor J2EE y ejecute el siguiente comando para e j e c u t a r ~ r o x ~ o ~ i c ~ u b 1 i s h e r :


j3
-

- E ~ j r n , ? . p r , ~ p e r t i e s = ~ ? ; E E , - H O l . ~ 1 E ' \ : : r t f i 3 \ j r n s - = l i e n t . p r c , p i i - f ii.? -ct . ; P J T E E IIOMEP\lib\j?;~?.i.ir; I ~ ! ~ , . ~ : , T ~ ? ~ ~ i r E ~ ~ i : ~ l i : ~ h e r

Debe poder ver algo ask

Una vez mas, 10s tres mensajes que hemos creado y enviado al apartado W r o x P u b l i c a t i o n s han desparecido porque n o hay nada que 10s suscriba al apartado (hasta, por supuesto, que creemos y e~ecuten~os~rox~opic~ubscriber). Aunque hemos e s p e c i f i c a d o ~ e l i v e r y ~ o d .PERSISTENT: e

el mecanismo publicar/suscribir s610 mantendri o retendri mensajes que tengan suscriptores, por lo que

incluso 10s mensajes que no expiren desaparecerin si son enviados a un apartado sin suscriptores.

El c6digo para implementar nuestro suscriptor de apartado es similar a1 de ~ r o x ~ u e u e ~ e c e i Una v e r ~ vez mas, anadiremos algunas funciones mis, esta vez con el objetivo de mostrar selectores d e mensaje y suscripciones duraderas:

public c l a s s W r o x T o p l c S u h s c r i b e r I p8.1blic s t a t i c void r n a i n l s r - f i n s [ ] a r g s ) I Topic topic = null; T n p i c C o n n e c t i o n f a c t o r y t o p i c C n n n e c t i o n F a c t o r y = null; T o p i c C o n n e c t i o n topicCannection = n u l l ;

JMS y beans controlados por mensaje


Context jndicontext = n e w InitialContext ( 1 ; topicConnectionFactory = ( T o p i c C o r ~ n e c t i o n F a c t o r y ) j r~3iCor~text. lookup ( " T o p i c C o r ~ n e c t i o n F ' a c t o r y "; ) topic = ( T o p i c ) j ndiContext. l o o k u p ( " W r o x P ~ ~ t i l i c a t i o n s; ") 1 catch (NamingEzception nEx) [ System. out. println (r1Ex. tostring ( ) tf'\r~Doesthe topic e x i s t ? " ) ; System.exiti1); try i topicConnection = topi cConnectionFactory. c r e a t e T o p i c C c c r ~ r ~ e c t i o ( r ) ~ ; TopicSession topicSession = topicCor~nection.createTopicSessior (false, ~ Session.AUTOACKNOWLEDGE);

Todo hasta el momento ha sido igual, excepto, por supuesto, las sustituciones de apartado/cola. A continuacion, creamos cuatro T o p i c S u b s c r i b e r s ; el primer0 es un suscriptor duradero (del que hablaremos mis adelante) que escuchari mensajes alli donde la p r o p i e d a d ~ e t a ~ acontiene ta la palabra J Z E E . El segundo T o p i c s u s b c r i b e r esti configurado para escuchar libros publicados en "Alsaciano" (un dialect0 alemin hablado en Francia oriental). El tercero escucha cualquier libro que contenga la palabra "Java" y el ultimo simplemente escucha todo (por defecto):
TopicSubscriber topicSubscriberDurableJ2EE = topicSession.createDurableSubscriber(topic, "Wrox", "MetaData LIKE false); TopicSubscriber topicSubscriberAlsacien = topicSessior~.createSubscriber(topic, "Languages LIKE false); TopicSubscriber topicSubscriberJava = topicSessiar~.createSubscri~er(topic, "MetaData LIKE false);

'%JZEE%"',

'%Alsacien%"',

'%Java%"',

Si se esti preguntando cuil es el liltimo parimetro, el parimetro " n o ~ o c a " l permite que 10s mensajes procedentes de la conexion local (la suya propia) Sean aceptados o bloqueados; en este caso, f a l s e significa que 10s mensajes locales estin permitidos. Ahora necesiramos configurar cuatro oyentes distintos. El constructor de la clase oyente toma un parimetro name para capacitar la identificacibn de una determinada instancia:
topicSubscriberDurableJ2EEEsetMessageLister~er( new WroxTopicI~istener("Durable, J2EE" ) ) ; topicSubscriberAlsacien.settopicSubscriberAlsacien.setMessagelistenMes~aqeLi~tener( new WroxTopicListener("a1sacien")); topicSubscriberJava.setMessageLister(new WroxTopicListener("Java"j); topicSubscriberAll.setMessageListener(rew WroxTopicListener("A11"));

System.out.println("Waitir~g I minute for messages.. for (int i = 60; i > 0; i-) { System.out.print("Count down . . . "ti+" \rt');

." 1 ;

Capitulo 19

catch (JMSException j m s E x ) I System.out .println("Exception: " 1 catchiException lazy) I S y s t e m . o u t .printlr~("Exception: " ] finally I if (topicConnection ! = null) I try I topicConnection.close(); ) catch (JMSException e ) ( I
]

t t

jmsEx. tostring ( lazy. tostring (

) ) ;

) ) ;

I
I

Es necesario que creemos nuestro nuevo oyente, W r o x T o p i c L i s t e n e r :


import j ava. util. D a t e ; import j avax. j ms. * ; public c l a s s WroxTopicListener implements MessageListener private String name; public WroxTopicListener[String name) { this.name = name; System.out.println[namet" MessageListener
{

created");

public void onMessage(Message message) { try { TextMessage textMessage = (TextMessage) message; System.out.println(name + " -> " t textMessage.getText()); I catch (JMSException jmsEx) { System.out .println ("JMSException in onMessage ( ) : " + jmsEx.toString() ) ; 1 catch(Exception e ) { System.out.println ("Exception: " + e. tostrirlg ( ) ) ; 1

Hay algo mis que tenemos que hacer antes de poder ejecutar este ejernplo. Los suscriptores duraderos deben tener un ID de cliente para identificarlos. El ID de cliente es el context0 del suscriptor para diferentes sesiones; recuerde que podriamos regresar a una suscripci6n que hayamos configurado hace a@n tiernpo en una sesi6n o aplicaci6n totalrnente distinta. Analizarernos con detalle las suscripciones duraderas rnuy pronto pero, por el mornento, podernos configurar prograrniticarnente el c l i e n t ID utilizando:
j avax. jms. C o n n e c t i o r ~ . setC1ientID("WroxX')

Sin embargo, hay una serie de condiciones que hacen que este enfoque prograrnitico sea proclive a generar excepciones. Por lo general, el rnodo rnis fiable de realizarlo es utilizando la herrarnienta j 2 e e a d m i n :
j2eeadmin -addjmsFactory TopicConnectionFactory topic -props clientId=Wrox

Ejecute este cornando para configurar una propiedad c l i e n t I D parawrox. Se configura corno una propiedad de c o n n e c t i o n F a c t o r y . Ya estarnos preparados para cornpilar y ejecutar el consurnidor

JMS y beans controlados por mensaje

No se recibe ninglin mensaje porque el apartado ~ r o x ~ u b l i c a t i o n ns o tiene n i n g l h suscriptor por el


momento. Pero si volvemos a ejecutar ~ r o x ~ o p i c ~ u b l i s h e r :
j ava

- P j m s . p r o ~ r r t i e s = ' 3 J 2 E , EHOE.IEY.\i'r.rtf i 7 \ j m z -c l i e n t . Fr - i f p e r t i e s i suhbel r ;I J 2 E F- M O i 4 E ? \ l i b \ T 2 e e ,+ r ; ~ : J ~ i ~ ~ T o p i c P -cp

.>

y despu& ejecute d e n u e v o ~ r o x T o p i c S u s b c r i b e r :
j aT?a

-Cjm? . p r . ~ p ~ r t i ~ . = = ? ~ 7 2 E E - H O I ? E P \ 1 iz qr \~ jn mf -~c l i e r l t . ~ r i l p r r i te s
-.zrr
.;4J:EF:
-

HOP:F*?lik,\jLre.jRT;

!'!r~?:.:T~~pi~S'~hss:rit.er

Debe ver algo asi:

Capitulo 19
La primera vez que s e ha e j e c u t a d o ~ r o x ~ o p i c ~ u s b c r i b se e ha r , suscrito indefinidamente al apartado W r o x P u b l i c a t i o n s . Lo que hace el suscriptor duradero es configurar una conexidn que permanece efectiva hasta que invocamos explicitamente el m t t o d o u n s u b s c r i b e ( ) . Esto significa que el proveedor JMS es responsable de almacenar y posteriormente reenviar 10s mensajes perdidos o n o expirados cuando el suscriptor, identificado por el mismo c l i e n t ID,renueve su conexion. Corno sugiere su funcionalidad, esto se conoce c o m o mensajeria de almacenamiento y reenvio y, en lo que se refiere a funcionalidad, es similar al m o d 0 que funcionan las colas. La mensajeria d e almacenamiento y reenvio es una parte fundamental de las soluciones d e mensajeria d e hoy en dia, puesto que el hecho d e que 10s rnensajes lleguen independientemente d e la durabilidad d e la conexidn proporciona una base perfecta para la conectividad B2B fiable. Para retirar la suscripci6n a una conexidn duradera, tendriamos primer0 que cerrar el suscriptor, asi:

bd ee r s p u ~ s ~ r o x ~ o p i c ~ u b l i obtenemos sher, 10s siguientes Si e ~ e c u t a m o s ~ r o x T o p i c ~ u b s c r iy resultados:

I
I

El orden d e 10s mensajes serP aleatorio porque 10s mensajes se reciben asincr6nicamente. P o d e n ~ o s ver que, salvo " A 1 1 " W r o x T o p i c L i s t e n e r , cada oyente ha recibido 10s mensajes a 10s que selectivamcnte se ha n erecibido r 10s mensajes. suscrito. E s t i claro que m i s de un s u s c r i p t o r ~ r o x ~ o p i c ~ i s t e ha Para alcanzar la selectividad, utilizamos un selector d e mensajes. Puede configurarse durante el m t t o d o c r e a t e s u b s c r i b e r ( ) . Los selectores d e mensaje son extremadamente capaces y proporcionan posibilidades ilimitadas d e seleccionar mensajes. La sintaxis estP basada e n un subgrupo d e SQL-92. Esencialmente, utjliza t o d o lo que encontrariamos normalmente despues d e la i n s t r u c c i d n " ~ ~ en ~~~" SQL-92 normal. Estos s o n algunos ejemplos:
Price . I 50 P r i c e BETWEEN 1 5 A N D 5 0 F r i c ? < 50 OR ( P r i c e < S O C u r r e n c y IN I ' C A D ' , 'GBP' JMSFriori ty=q Title NOT NULL

AND M e t a O a t a L I K E '%Java%')
'AYD'

'NZD'

'INRI )

Las propiedades de usuario, n o s61o puede utilizarse para seleccidn, sino que algunas de las propiedades fijas del mensaje, c o m o P r i o r i t y , tambitn pueden utilizarse. Otras que pueden ser incluidas:

JMS y beans controlados por mensaje


JMSDeliveryMode,JMSPriority,JMSMessage,JSCorrelationIDy

JMSType.Algunas de estas propiedades pueden devolver el valor n u 1 1,asi que, si queremos tener criterios fiables de selection debemos utilizar 10s operadores I S NULL o NOT NULL.

Puede encontrar 10s detalles completes en el Javadoc de la interfaz Message y en la secci6n 3.8.1.1 de la especificacidn J M S (viase http:lljava.sun.comlproductsljmsldocs.html).

Las interfaces JMS forman parte del paquete j avax . jms.Aqui presentamos algunos de 10s mktodos mis complejos, inusuales o exhaustivos de la interfaz. La,mayoria de las interfaces que faltan y algunos de 10s mktodos que faltan, son 10s XA (transaccionales). Estos son por lo general versiones XA de las interfaces o mitodos estindar (distintos de XA) y son utilizados al incluir transacciones JMS en una transacci6n Java Transaction Service (JTS). El proveedor JMS expone su compatibilidad JTS utilizando XAConnectionFactory JMS, que es utilizada por un senidor de apkaci6n para crear una XASess ion. Interfaz
BytesMessage Connection

Descripci6n Utilizadapara enviarun mensajequecontengaun streamde bytes sin interpretar. Una conexi6n activa del cliente a su proveedor JMS; incluye 10s siguientes mktodos:
void setClientID (String clientID) ,configuraelIDdelclientepara la conexi6n. El modopreferido de configurar el IDE cliente consiste en configurar Connect i onFact or y utilizando las herramientas de administraci6n JMS provistas. Si el I D del cliente ha sido configurado por la herramienta de configuracibn, al invocar este metodo se genera una excepci6n IllegalStateException. void start ( ) ,inicia o reinicia la entrega de mensajes de la conexihn. void stop ( ) ,interrumpe temporalmente laentregade rnensajes delaconexibn;

sin embar o, se bloquea hasta que recibe un mensaje y l o hasta que se hayan completa o todos 10s oyentes de mensaje en funcionamiento. Interrumpir una sesi6n no tiene ningun efecto sobre su capacidad de enviar mensajes e invocar st art ( ) marcari el reinicio.

Connection Factory Connection MetaData DeliveryMode

Encapsula un conjunto de parimetros de configuracidn que han sido definidos por un administrador. Proporciona informaci6n que describe la connect ion. Modos de entrega apoyados por JMS, sencillamente PERSISTENT y N O N PERSISTENT. El mod0 de entrega s610 cubre el transporte del mensaje a su destino. Encapsula direcciones especificas del proveedor puesto que JMS no define una sintaxis estindar de direcci6n. Aunque consider6 una sintaxis estindar de direcci6n, decidi6 quelas diferencias en la semanticade direcciones entre productos M O M existentes eran demasiado dificiles de eliminar con una unica sintaxis. Si un proveedor JMS detecta un roblema grave con unaconnect ion,informari a1 ExcevtionListener de a conexi6n. si se ha registrado una.

Destination

Except ion Listener

tabla continua

siguiente

Capitulo 19
Interfaz
MapMessage

Descripcih
Utilizada para enviar un conjunto de pares valor-nombre donde 10s nombres son cadenasy 10s valores son tipos de primitiva Java. Se puede acceder a las entradas de valor nombre secuencialmente por enumerador o por nombre. La interfaz raiz de todos 10s mensajes JMS. void correlation^^) configuraelID ue setJM~~orrelation (string 1~ podia haber sido configurado por el proveedor JMS (si se ajusta a lor I D ge mensaje o por el cliente JMS utilizando el metodo de confi uraci6n. Se utiliza a menu o para correlacionar de aplicacih a aplicacibn. poiria utilizarla para identificar un mensaje de respuesta auna solicitudprevia; el I D de la solicitud se utilizaria en la respuesta. La respuestapodria llegar despues de la solicitud y el I D de correlacion es un buen modo de llgar ambos elementos. Los valores especificados en la aplicacion no deben comenzar con el prefijo "ID : ";queda reservado para valores de I D de mensajes generados por el proveedor.

Message

Un cliente utiliza un consumidor de mensajes para recibir mensajes desde un Destino; un consumidor de mensajes es asincrono y proporciona metodos comoreceive ( ) yreceiveNoWait ( ) .
Message Listener

Utilizada para recibir mensajes recibidos asincr6nicamente; so10 hay un mensaje definido por esta interfaz, o m e s s a g e ( ) . U n cliente utilizaunproductor de mensajeparaenviarmensajes aunDestino.
void setDeliveryMode (int deliveryMode) configurael modo de entrega. Opciones vilidas son Del ive ryMode .NON-PERSISTENT y De1iveryMode.PERSISTENT. void setDisableMessageID (boolean value) esparaactivar/desactivar 10s I D del mensaje. Puede utilizarse para reducir el tamafio del mensaje y, en ocasiones, para aumentar el rendimiento. void setDisableMessageTimestamp(boolean value),esparaactivar/ desactivar las estampillas de tiempo del mensaje. Puede utilizarse para reducir el tamafio del mensaje y, en ocasiones, para aumentar el rendimiento. void setpriority (int defaultpriority) ~ o n f i ~ u r a e l m e n s a j e d e prioridad pordefecto.0 es elvalor mis bajo,O-4 son grados de prioridad "normal", 5-9 son considerados prioridad " r i ida" Para prioridad normal utilizar Message. DEFAULT-PRIORI&. . void setTimeToLive (long timeToLive) confi u r a e l t i e r n p ~ d e v i d a ~ o r defecto en milisegundos. Configurar el tiempo de vifa en cero (el valor por defecto) significa efectivamente "ilimitado".

Utilizada para enviar un mensaje que contiene un objeto Java serializable. Si se necesita una coleccion de objetos Java, podemos utilizar una clase de coleccih Java.
Queue QueueBrowser Queueconnection

Encapsula un nombre de cola especifico del proveedor. U n cliente utiliza un QueueBrowser paraexaminar mensajes en una cola sin eliminarlos. Una conexi6n activa a un proveedor JMS punto-a-punto.

JMS y beans controlados por mensaje


Interfaz QueueConnection Factory Descripcibn U n cliente utiliza unaQueueCo n n e c t i o n F a c t o r y ara crear Q u e u e c o n n e c ti o n s c o n u n P r o v e e d o r P ~JMS P con E s sipientes mktodos: QueueConnection c r e a t e Q u e u e C o n n e c t i o n ( )
QueueConnectioncreateQueueConnection(StringuserName, Stringpassword)

QueueReceiver Queuesender

U n cliente utiliza un Q u e u e R e c e i v e r para recibir mensajes que han sido entregados a una cola. U n cliente utiliza un Q u e u e s e n d e r para enviar mensajes a una cola. v o i d s e n d ( Q u e u e queue, Messagemessage, i n t d e l i v e r y M o d e , i n t p r i o r i t y , l o n g t i m e T o L i v e ) enviaun mensajeaunacolaparaun productor de mensaje no identificado, especificando mod0 de entrega, pr~oridad y tiempo de vida. Proporciona mktodos para crear Q u e u e R e c e i v e r s , Q u e u e s e n d e r s , QueueBrowsersyTemporaryQueues. QueueBrowser c r e a t e B r o w s e r ( Q u e u e queue, S t r i n g m e s s a g e S e l e c t o r ) crea unQueueBrowser paranave ar,peronoconsumir, mensajes en una cola con un selector de mensaje especi KO.

Q u e u e c r e a t e Q u e u e ( S t r i n g queueName) ; p ~ o ~ i s t o p a r a c a s ~ s r a r o s e n 10s que clientes necesitan manipular dinimicamente a ~ d e n t ~ d de a dla cola. Suuso no es portitil. TemporaryQueue c r e a t e T e m p o r a r y Q u e u e ( ) creaunaco~atempora~cuya duracidn de vida no es superior que la de Q u e u e c o n n e c t i o n . Session U n context0 de hilo Gnico para producir y consumir mensajes. v o i d r e c o v e r ( ) ,interrumpela entregade mensajes enestasesi6nylareinicia enviando mensajes con el mensaje adm~tido mas antiguo. v o i d s e t M e s s a g e L i s t e n e r ( M e s s a g e L i s t e n e r l i s t e n e r ) ;utilizado con poca frecuencia, mis a menudo utilizado por sewidores de aplicacidn. StreanMessage TemporaryQueue TemporaryTopic TextMessage Topic TopicConnection TopicConnection Factory; TopicPublisher Utilizado para enviar un flujo de primitivas Java. U n objeto exclusivo~ueue creado para la duracidn de u n a ~ u e u e c o n n e cito n . U n objeto e x c ~ u s i v o ~ o creadopara ~ic l a d u r a c i d n d e u n a ~ o p i c ~ o n n eic otn . Utilizada para enviar un mensaje que contengan un s t r i n g . Encapsula un nombre de apartado especifico del proveedor. Una conexi6n activa a un ~ r o v e e d oJMS r pub/sub. U n cliente u t i ~ i z a u n a ~ o ~ i c ~ o n n e c t i o n ~ paracrear actory T o p i c c o n n e c t i o n s con un proveedor JMS pub/sub. U n cliente utiliza u n T o p i c Pub1 i s h e r parapublicar mensajes en un apartado. v o i d s e n d ( T o p i c t o p i c , Message message, i n t deliveryMode, i n t p r i o r i t y , l o n g t i m e T o L i v e ) enviaunmensajeaunapartadopara un productor de mensaje no identificado, especificando mod0 de entrega, prioridad y tiempo de vida.

La tabla continua en la pdgina siguiente

1027

Capitulo 19

Interfaz TopicSession

Descripci6n ProporcionamCtodos p a r a c r e a r T o p i c P u b l i s h e r s , T o p i c S u b s c r i b e r s y TemporaryTopics. TopicSubscriber createsubscriber (Topic t o p i c , S t r i n g messageSelector, boolean n o l o c a l ) creaunTopicSubscriber para el apartado especificado utilizando selectores de mensaje. El parimetro n o l o c a l permite ue 10s mensajes procedentes de la conexion local (la suya propia) Sean acepta%os o bloqueados.
TopicSubscribercreateDurableSubscriber ( T o p i c t o p i c , S t r i n g n a m e , S t r i n g m e s s a g e s e l e c t o r , b o o l e a n n o l o c a l ) creaun T o p i c S u b s c r i b e r duraderoparaelapartadoespecificado.Elnombreprovisto debe corresponder con el ID cllente de laconexi6n (vtase ejemplo anterior). El parLmetronoLoca1 permite que 10s mensajes procedentes de laconexi611local (la suya propia) Sean aceptados o bloqueados.

TopicSubscriber

U n cliente utiliza u n T o p i c S u b s c r i b e r para recibir mensajes que han sido publicados para un apartado.

Utilizar transacciones con JMS


El mod0 m6s sencillo de utilizar JMS con transacciones consiste en utilizar una sesi6n JMS transaccionada. Sin embargo, esto nos lirnita a JMS. Es decir, podernos agrupar mensajes y realizarlos o deshacerlos. Esto es bastante restrictivo. Por ejernplo, podriamos n o consurnir un mensaje y entonces grabarlo en la base de datos en una h i c a transacci6n; esto requiere el uso del Semicio de Transacciones Java (JTS). Crear una sesi6n JMS transaccionada es bastante sencillo; el primer parirnetro del rnttodo c r e a t e X X X S e s s i o n ( ) puede utilizarse para configurar una sesi6n transaccionada:
Queuesession queuesession
=

TopicSession topicsession

connection.createQueueSession( true Session.AUT0 ACKNOWLEDGE conr~ection.create'~opicSession( true, Session.AUT0ACKNOWLEDGE

);

);

Los rnensajes enviados o recibidos utilizando esta sesi6n son agrupados autorniticarnente en una transacci6n. Es irnportante sehalar que no hay ninghn rnttodo b e g i n ( ) :
TextMessage textMessage1 TextMessage textMessage2 TextMessage textMessage3
= = =

queueSession.createTextMessage(); queueSession.createTextMessage(); queueSession.createTextMessage();

textMessagel.setText("Send J2EE book to client 45827"); textMessage2.setText("Reduce J2EE book stock by 1 " ) ; textMessage3.setText("Add $49.95 client 45827's bill"); queuesender. send (textMessage1); queueSender.send(textMessage2); queueSender.send(textMessage3);

Estos tres mensajes anteriores pueden realizarse utilizando c o m m i t ( )

JMS y beans controlados por mensaie


q u e u e s e n d e r . commit ( ) ;

o anularse con r o l l b a c k 0:
queueSender. r o l l b a c k ( ) ;

TextMessagel, TextMessage2 y TextMessage3 sonahoraenviados (orecibidos) comounsologrupo.

N o estamos limitados simplemente a enviar o recibir. Podemos combinar ambas acciones y vincular recibir y enviar en una sola transaccidn. Esto resulta Gtil cuando estamos reenviando mensajes en una pasarela. O t r o uso es el de vincular colas a apartados. Por ejernplo, llegan noticias a la cola y despuks son "transmitidas" a 10s suscriptores de un apartado determinado en una Gnica transaccidn. Si algo falla en la publicacidn, el mensaje n o seria leido desde la cola (suponiendo que tuviera lugar la llamada a rollback 0).

Tres implementaciones JMS de peso industrial


Existen mis de una docena de buenas implementaciones JMS entre las que poder elegir. Nuestra eleccibn de proveedor dependeri ampliamente del uso: algunas son gratuitas, otras de c6digo abierto, otras disefiadas para mayor rendimiento y/o fiabilidad, y otras son vendidas como parte de mayores aplicaciones o servidores de aplicaci6n. Las tres siguientes son ficiles de descargar e iniciar (aunque SonicMQ y SpiritWAVE requieren claves de licencia para su uso, claves que son ripidamente proporcionadas y sin ningGn tip0 de problema). Todas ellas son implementaciones profesionales y todas de base Java. Para cualquier situacidn concreta, probablemente haya un JMS que sea ligeramente m i s ripido, m6s fiable o que se reajusta mejor que el resto. Estas son algunas de las cuestiones que nos plateamos a1 elegir un JMS:
O

iPuede clasterizarse el servidor de destino? i C o m o se reajusta la clusterizacibn?

CI iQuk sistema operativo recomienda en proveedor?


0
O
E I

iRealmente necesita todas las funciones bonitas per0 n o estindar? Si estamos buscando velocidad, inecesitamos mensajeria punto-a-punto o pub/sub? iQuk sucede con el rendimiento cuando empieza a afiadir selectores de mensaje? iQuk ocurre cuando afiade un suscriptor duradero? proveedor en la fiabilidad en lugar de la velocidad?

o Si la pkrdida de un mensaje o la entrega de un duplicado puede costarle dinero, ise centra en


Es importante probar cualquier implementaci6n JMS en un entorno real con condicionas tan cercanas como sea posible a la soluci6n deseada.
Examinemos ahora m5s de cerca tres de estas implementaciones JMS.

SwiftMQ (http://www.swiftmq.com), en contraste con sus competidores, es totalmente gratuito. N o s610 su desarrollo es gratuito, sino tambikn su implementacidn. La licencia establece lo siguiente:

Capitulo 19
"SwiftMQ Binary Code License Agreement. SwifiMQ es completamente (lit.) GRATISpara uso privado y comercial asi como para implementacidn y asociacio'n con su producto comercial o servidor de aplicacidn de cddigo abierto."
La ultirna versi6n,2.01, implementa a1 cornpleto la rnensajeria punto-a-punto y publsub para la version de la especificacion 1.0.2 e integra un rico conjunto de utilidades, todas ellas ficilmente configurables a travks de archivos de propiedad, una interfaz de linea de comando (CLI) y el GUI que utiliza SwiftMQ Explorer. La docurnentacion, en forrnato Javadoc, es ficil de seguir y rnuy completa. TarnbiCn se puede descargar. del misrno sitio SMTP Mailer Extension, que proporciona un puente SMTP que perrnite el envio de e-mail desde clientes JMS. Por ejernplo:
Q u e u e s e n d e r s e n d e r = session.createSender(rnai1Queue); T e x t M e s s a q e msq = s e s s i o n . c r e a t e T e x t M e s s a q e ( ) ; m s g . s e t S t r i n g P r o p e r t y ( " f r o m " , " r e a d e r @ w o r k . c o r n " ); msg. s e t S t r i n g P r o p e r t y ( " t o " , " J o h n @ C 2 4 S o l u t i o r ~ .c so r n t ' ) ; r n s g . s e t S t r i n g P r o p e r t y ( " r e p l y t o " , " r e a d e r @ h o r n e . c o r n " ); r n s g . s e t S t r i n g P r o p e r t y ( " c c " , "Wayne . M e i k l e @ C 2 4 S o l u t i o n s .corn") ; r n s g . s e t S t r i n g P r o p e r t y ( " s u b j e c t " , "JMS"); rnsq. s e t T e x t ( " T h i s JMS API i s q r e a t s t u f f ! " ) ; s e n d e r . s e n d (rnsg);

Existe tambikn una extension puente JMS que proporciona funcionalidad de puenteado entre SwiftMQ y cualquier sistema externo que se adapte a JMS 1.0.2. SwiftMQ esti preconfigurado con dos colas, un apartado y una cornpleta serie de ejernplos para iniciarse. A partir de su descarga, en tan s610 unos minutos despues de su instalaci611, puede ejecutarse. Modificar 10s ejemplos y las colas provistas es el rnodo mis ficil de ernpezar a partir de ahi. Y lo fundamental sigue siendo que es completamente gratuito.

SpiritWave
SpiritWave de Spiritsoft ( h t t p : / / ~ ~ ~ . ~ p i r i t - S O es ~una .CO las ~) irnplementaciones rnis cornpletas en tkrrninos de irnplementacion central y funciones extendidas. SpiritWAVE, completamente adaptado a JMS 1.0.2, arnplia el apoyo a XA, a tunelizacion HTTPI Cortafuegos y SSL, relevo dinamico, tolerancia a fallos y clustering o operation de agrupamiento. Otra caracteristica es su compatibilidad con controladores conectar-y-usar y transforrnaciones para rnensajeria de legado con, por ejemplo, Tibco Rendezvous 5.x, 6.x y ETX, IBM M Q Series, MSMQ, Talarian SrnartSockets, y WebMethods Activeworks. Tarnbien se integra en varios semidores de aplicacion y, algo muy interesante, tiene adaptadores SpiritWave JMS para aplicaciones Microsoft C O M . Hay varias extensiones para las capacidades del selector del JMS. Por ejernplo, puede realizar selecciones avanzadas basindose en el contenido XML del cuerpo del rnensaje. Estas irnportantes caracteristicas permiten, por ejemplo, el direccionamiento de mensaje basado en contenido XML, per0 esto conlleva el coste de la portabilidad en irnplernentaciones JMS. SpiritWave integra un arnplio conjunto de ejemplo y la docurnentaci6n se encuentra en formato PDF.

SonicMQ de Sonic Software (http://www.sonicsoftware.com) es probablemente la implernentaci6n JMS rnis conocida. SonicMQ es tarnbikn una implementacibn cornpleta de la especificaci6n JMS 1.0.2 con apoyo XA. Cuenta con excelente documentacion (en forrnato PDF) y tarnbikn inchye codigo de muestra instructivo.

JMS y beans controlados por mensaje


SonicMQ hace alarde de mensajeria XML integrada, arquitectura dinimica de direccionamiento (DRA), clusterizacidn y apoyo completo a PKI y SSL. SonicMQ tambikn puede integrarse con puentes, como IBM M Q Series y servicios de correo FTP y SMTP.

Beans controlados por mensaje


DespuCs de examinar algunos de 10s API controlados por mensaje (MDB), examinaremos el ciclo de vida de un MDB y veremos un sencillo ejemplo que demuestra su uso con transacciones EJB. Los beans controlados por mensaje fueron introducidos en la especificacidn EJB en la versidn 2.0; el objetivo era proporcionar un mecanismo para el manejo asincrono de mensajes en EJB. Esto complementa 10s beans existentes de Sesidn y de Entidad disponibles en EJB 1.0, 1.1 y 2.0.

El bean controlado por mensaje es, esencialmente, un oyente de mensajes que puede consumir mensajes de una cola o de una suscripci6n duradera a travis del contenedor J2EE; el contenedor invoca a1 bean como resultado de la llegada de una mensaje JMS.
El cliente percibe el bean controlado por mensajes como un consumidor JMS que implementa 16gica de empresa per0 que s61o puede comunicar con el bean enviindole un mensaje a travCs de JMS. Los beans controlados por mensaje pueden comunicar con beans de sesidn y con beans de entidad para ampliar la 16gica de empresa o para proporcionar cierta forma de persistencia de aplicaci6n.

Los beans controlados por mensaje son anbnimos, no tienen estado conversacional con el cliente y puede ser reservados como beans de sesi6n sin estado. A diferencia de otros tipos de EJB, 10s beans controlados por mensaje no tienen interfaces iniciales ni remotas. Debido a la carencia de estas interfaces de lado cliente, 10s clientes no pueden interactuar con ellos; el bean es invocado con la llegada de un mensaje.
El contenedor EJB realiza las funciones de reserva de recursos, seguridad y gesti6n de transacciones, y mantiene el ciclo de vida de 10s beans controlados por mensaje. Los beans controlados por mensaje no son ideales para situaciones que requieren que multiples colas o apartados sean atendidos por un h i c o consumidor JMS. En este caso, una mejor opcidn seria utilizar varios beans controlados por mensaje para cada cola o, simplemente, utilizar consumidores JMS "estindar". Los MDB esti tambikn bastante limitados por el hecho de que la cola o el apartado son definidos en el descriptor de implementaci6n en el periodo de implementaci6n en lugar de en el periodo de ejecuci6n. Y, lo que es peor a h , 10s selectores de mensaje tambiCn son definidos en el descriptor. Esta es una las caracteristicas mis importantes de JMS y e s una pena que sea fijado en el descriptor de implementacidn. Existen formas de evitar esto en la mayoria de servidores de aplicacidn pero, si utilizamos estas opciones, estamos desviindonos de la especificaci6n J2EEIEJB y corremos el riesgo de atar nuestra aplicacidn a una implementaci6n especifica. Los beans controlados por mensaje deben implementar j avax .jms .MessageListener y javax. e j b .MessageLjstener.Elcuerpo delreceptores i m p l e m e n t a d o e n e l m C t o d o o ~ e s s a g e( ) de Mes s ageLi s tene r. Este no debe generar excepciones JMS o de aplicaci6n; en su lugar, las excepciones deben ser capturadas y, preferiblemente, procesadas. Como minimo, deben volver a generase como EJBExcept ion. U n MDB "bien educado" (corno otros EJB) no debe generar una excepcidn
RuntimeException.

Capitulo 19
MessageDri~enBeanes~ecific s61o a dos mitodos:
0
0

void e j bRemove ( ) es invocado por el contenedor justo antes de que el bean sea eliminado void setMessageDrivenContext (MessageDrivenContext ctx) configuraelcontexto para el bean

Finalmente, es necesario definir 10s mitodos de creaci6n y elimination. Las firmas relevantes son:
0

public void ejbcreate ( ) Donde debe crear las conexiones JMS si pretende enviar mensajes desde este bean public void e jbRemove ( ) Donde debe cerrar cualquier conexi6n realizada en el metodo e jbCreate ( )

N o hay ning6n otro mttodo de empresa en el MDB. Pueden definirse otros mCtodos para proporcionar funcionalidad de empresa pero, normalmente, s610 serian invocados desde onMessage ( ) ya que este mensaje es el unico modo de comunicar con el bean.

Ciclo de vida del bean controlado por mensaje


El EJB controlado por mensaje se inicia con la invocaci6n de 10s siguientes mitodos:

En este punto, hay una instancia MDB en la reserva preparada para mCtodos del contenedor, preparada para procesar mensajes desde su destino. El contenedor invoca e j b R e m o v e ( ) cuando ha terminado con el EJB:

onMessaqe ( ) ' , I

f! Reserva preparada r para rnetodos

Transacciones en beans controlados por mensaje


Hay dos tipos de gesti6n de transacciones para beans controlados por mensaje:
0

Gestionadas por bean

JMS y beans controlados por mensaje

Gestionadas p o r contenedor

afectan a 10s atributos transaccionales del metodo onMessage ( ) y a1 manejo de la entrega de mensajes garantizada.

st as

Transacciones gestionadas por bean


Los limites transaccionales deben ser definidos en el metodo omessage ( ) y realizados o anulados antes d e que devuelva u n valor. La entrega del mensaje n o e s t i garantizada porque el proceso de desacolaci6n e s t i fuera de 10s limites transaccionales, a menos que se utilice j avax. transaction. user~ransaction. Siseutilizaj avax.transaction .user~ransaction, una aplicaci6n cliente puede demarcar explicitamente 10s limites de la transacci6n.

Transacciones gestionadas por contenedor


Este tip0 garantiza la entrega del mensaje. So10 estin permitidos aqui dos atributos transaccionales: NotSupported y Required. Los beans controlados por mensaje no propagan transacciones distribuidas. E n el caso de NotSupported,el bean es ejecutado sin una transacci6n. Si se configura Required,el bean es ejecutado en una nueva transacci6n.

Un ejemplo de bean controlado par mensaje


Lo finico que vamos a hacer en este ejemplo tan sencillo es imprimir el tip0 de mensaje y, en la mayoria de 10s casos, el contenido de mensaje para system.out.Si se e s t i preguntando ddnde estin todas las factorias de conexion y las conexiones, la respuesta es que son configuradas en la fase de irnplernentaci6n del bean. EI siguiente c6digo corresponde a nuestro e j e r n p l o ~ e s s a g e ~ r i v e n ~ r o x ~ e a n :
import j a v a x . e j b . + ; import j avax. jrns. + ; import j avax.narning. '; public class Mess3qeDrivenWroxBear~ implements MessageDrivenBean, privat.e MessageDrivenContext ctx;

MessageListener

publiz void setMessageDrivenContext (MessageDrivenContext c t x ) { this.ctx = ctx;


1

public vbld ejbCreate ( ) throws CreateException { Systern.out .println ("Message-Priven bean created") ;
1

public void onMessage (Message rnsg) { System.out.printlr~("Message received:

" ) ;

try i if (msg irjstanzeof TextMessage! { Systern.out.printlr~("TextMessa~~e: " + ( (TextMessage)msg).getText() ); 1 else if (msg instanceof ObjectMessage) { System.out .println ("ObjectMessaqe: " + ([ObjectMessaqe)rnsg).getObject(!); 1 else if (rnsg instanceof StrearnMessage) { System.out .println ("StrearnMessage: " + ((StreamMessage)rnsy).readStringi));

Capitulo 19
I
}

else if (msg instanceof BytesMessage) [ System.out.println("BytesMessage: "t( (BytesMessage)msg).readUT()) ; else if (msg instanceof MapMessage) ( System.out .println ("MapMessage: " t ( (MapMessageimsq) .getstring ( "msg4')) ;

1
}

catch(Exception any) [ System.out.println ["Exception: "


{ }

1 I
public void e j b R e m o v e 0

Implement,aciondel bean controlado por mensaje


Igual que ocurre con cualquier tip0 de EJB, escribirlo es s61o la mitad del trabajo; el resto esti en la implementaci6n. Compile su bean con el siguiente comando:
j avac -classpath

. ;% J2EE_HOME%\lib\j 2ee. j ar MessageDrivenWroxBean. j ava

Inicie entonces la herramienta de implementaci6n del servidor de la aplicaci6n; esto se realiza en la implementaci6n de referencia JZEE con el comando deploytool desde el directorio % J2EE-HOME% \. Asegfirese, llegado a este punto, de que esti trabajando con un servidor de aplicaci6n que se ajusta a EJB 2.0; de lo contrario, no veri las opciones de "bean controlado por mensaje". Algunos proveedores JMS de terceros ofrecen funciones MDB que complementan 10s servicios de aplicaci6n; no obstante, a medida que va pasando el tiempo, hay servidores de apkaci6n que se ajustan a MDB cada vez mis "reales". Las siguientes instrucciones se relacionan especificamente con la Implementaci6n de Referencia JZEE; otros servidores de aplicaci6n diferirdn en sus tkcnicas de implementaci6n y la documentaci6n relevante debe ser referida. Una vez se ha cargado la herramienta de despliegue, seleccione File (Archivo) I New (Nuevo) ( Application (Aplicaci6n) e introduzca ~ r o x ~ pseleccione p, despues File (Archivo) ( New (Nuevo) 1 Enterprise Bean. Esto le Ilevari a traves de una serie de cuadros de diilogo:

JMS y beans controlados por mensaje

A J A R file is requ~red to contain this enterprise bean. You can create a new JAR Rle withln an existing application or use an existing JAR file. Afler you have selected a JAR file, add Ihe EJB classes and any other desired Rles lo ~t's contents. Optionally, you can also provide a description, edit the manifest classpath, and choose icons lor the JAR file.
--.- - - -

Create new EJB File in Application

iJR OIsf~IayName: WrnxMDPean

9Add to Existing EJB File

0 Description...

1I

Manifest Classpat

Icons.,

Seleccione su nueva aplicaci6n e introduzca ~ r o x ~ ~ corno ~ e nornbre a n del bean. Pulse Edit (Modificar) y afiada su c l a s e ~ e s s a g e ~ r i v e n ~ r o x (el ~ earchivo an de clase, no la fuente Java), entonces pulse Next (Siguiente).

Capitulo 19

Please chnose the type olenterpr~se bean that you are creating ar~d select the class files from the JAR file that are tu be used for the bean. You can choose to provlde Only local interfaces, only remote interfaces, or both. Op11onally.you can provide a description and icons for the bean.

Y"hrFlC1@~;11?

I ' r n i o i ~lnrwf wrc

0Description...

1.-

--

mi, ...

Selcccione el tipo de bean Message-Driven, In clase de bean e introduzca el n o ~ n b r c de nuevo. Una vez m i s , hngn clic en Next p a continuar:

JMS y beans controlados por mensaje

Para 10s prop6sitos de nuestro sencillo ejeniplo, seleccione Bean-Managed y haga clic en Next:

Capitulo 19

Corw~ecl~on Factory.

QueueConnedionFactoly
Acknowl~tfg~rnertt:

I
JMS hlessaqe Selwlor:

I
I

Seleccione ahora la cola o el apartado desde el que desea consumir el mensaje. Tambien sera necesario que seleccione C o n n e c t i o n F a c t o r y y el metodo de acuse de recibo (para este ejemplo, seleccione AutoAcknowledge). Ya casi hemos Ilegado; en este punto, puede hacer clic en Finish (Finalizar). Ahora tiene un bean controlado por mensaje que esti creado per0 no implementado. Recuerde iniciar y conectarse, al servidor JZEE y, en la herramienta de implementaci6n, seleccionar el nuevo MDB. Seleccione entonces Tools (Herramientas) I Deploy (Implementar):

JMS v beans controlados por mensaie

Please select the object to be deployed and the s e m r to which it should be deployed:
Obiect to Denfov!

(0WrOXApP
Tarpet SBI%VT:

localhod

The server can send back a client J A R Ne. It contains the extra RMIlIIOP stub classes that client applications written In access this applicationwill need at runtime.

Esto nos permitirl implementar el bean en el contenedor JZEE; tomar la aplicacih que deseamos implementar y el servidor en el que varnos a hacerlo (probablemente localhost). C o m o siempre, haga clic e n Next, confirme que el nombre JNDI es correct0 y despubs haga clic en Finish para irnplementar su bean controlado por mensaje:

Capitulo 19

Contacted Server... Application WroxApp transferred WroxApp has 1 ejbs, 0 web companents to deploy Deploying Ejbs ... Processing beans ... Making client JARS ... Making senrer3ARs ... Deployment ofWroxApp is complete.

I ' m conlprobar que nuestro bean controlado por mensaje esti funcionando, debemos ver un mensaje con10 el siguiente en la ventana de comando desde la que hemos iniciado el servidor J2EE:

Si ejecuramos e l ~ r o x ~ u e u e ~ e nque d e hemos r utilizado anteriormente en este capitulo con el siguiente comando:

Debcmos ver que el Servidor J2EE imprime lo siguiente:

Si lo deja implementado en el servidor JZEE, cada vez que ejecute el servidor, tambitn se ejecutara este MDB. Si vuefve a ejemplos anteriores, n o veri sus mensajes porque este MDB 10s consumiri en su nombre.

JMS y beans controlados por mensaje


Veamos ripidamente el descriptor de implementaci6n. ~ s t es e un archivo XML que contiene la informaci6n de configuraci6n para el bean y ha sido creado por la herramienta de implementaci6n:
<ejb-jar>

<display-name>WroxMDBear~</display-name>
<enterprise-beans> <message-driven> <description>This is

the

Wrox

descriptior~</descriptior~>

<display-name>WroxMDBear~</display-name>
< e j b - n a m e > W r o x M D B e a r ~ < / eb-name> j bj- c l a s s > < ej b - c l a s s > M e s s a g e D r i v e r ~ W r o x B e a r ~ < / e <transaction-type>Bear~</trar~sactior~-type> <message-selector>Client NOT N U L L < / m e s s a g e - s e l e c t o r >

<ackr1owledge-mode>Auto-ackr1o~1edge</a~kr1owledge-mode>
<message-driven-dest i n a t ion> < d e s t i n a t i o n - t y p e > j a v a x . j ms. Q u e u e < / d e s t i n a t i o r ~ - t y p e > </message-driven-dest i r ~ a t i o r ~ > <security-identity>

<description></description>
<run-as> <description></descriptior~> <role-narne></role-name> </ r u n - a s > </security-identity> </messaqe-driven> </enterprise-beans> </ejb-jar>

Podemos ver que todos 10s parimetros que hemos configurado durante la implementaci6n del MDB han sido escritos en el descriptor de implementaci6n.

En este capitulo, hemos echado un vistazo a 10s primeros tiempos de la mensajeria, antes de ver c6mo JMS se ha convertido en el primer (y h i c o ) estindar M O M que cubre 10s dominios punto-a-punto y publicar/suscribir. Utilizando ejemplos sencillos, hemos experimentado de primera mano lo sencillo que es crear una sesi6n JMS, y producir y consumir mensajes. Tambikn hemos analizado la flexibilidad de 10s mktodos de consumici6n, sincronos y asincronos, y 10s importantes selectores de mensajes. En concreto, hemos analizado:

o Las diferencias entre dominios punto-a-punto y publicar/suscribir


0

Los bloques de construcci6n de la arquitectura JMS: objetos administrados, conexiones, sesiones, productores de mensajes, consumidores de mensajes y mensajes C 6 m o manejar mensajes asincr6nicamente (utilizando un oyente de mensajes) y c6mo utilizar 10s selectores de mensajes C 6 m o utilizar transacciones con JMS

Finalmente, hemos cubierto la 6ltima incorporaci6n a la familia EJB, 10s beans controlados por mensaje:
0

Hemos examinado el ciclo de vida de MDB

Hemos visto como crear e implements un sencillo MDB utilizando la Implementaci6n de Referencia J2EE

JMS se esti convirtiendo en una de las caracteristicas mls potentes e importantes de J2EE y, ciertamente, seri una importante tecnologia durante mucho tiempo. En el siguiente capitulo, analizaremos otra nueva caracteristica de J2EE 1.3, la Arquitectura de Conectores, que proporciona otro medio de integraci6n de las aplicaciones J2EE con sistemas de legado.

La arquitectura

Este capitulo presenta una introduccion a la Arquitectura de Conectores JZEE (JCA), una adici6n nueva y significativa a la plataforma J2EE en la versidn 1.3. JCA es una iniciativa de integration de aplicacion de empresa que proporciona una arquitectura estandarizada para capacitar a 10s componentes J2EE a tener acceso "conectar-y-usar" a Sistemas de Informacion de Empresa (EIS), que incluyen ERP, procesamiento de transacciones y sistemas de base de datos de legado. A lo largo de este capitulo, estudiaremos la Arquitectura de Conectores J2EE y desarrollaremos componentes de Conector J2EE para permitir que las aplicaciones J2EE integren e interactuen con recursos EIS. En concreto, nos centraremos en 10s siguientes puntos:

a
0 0 0 0 0 0

Temas de integracion EIS y el rol de JCA Arquitectura, servicios y API JCA Como funciona JCA en un sistema J2EE Programaci6n con la Interfaz Comfin de Cliente (CCI) Construccion de un componente JCA Reglas que debe seguir un desarrollador JCA Corn0 desplegar y probar componentes JCA

0 Ventajas potenciales del uso de JCA

Limitaciones actuales de JCA 1.1

La especificacion actual de la Arquitectura de Conectores esti disponible en el sitio Java de Sun en http:// java .sun.com/j2ee/connector/. Adicionalmente, existe una lista de vendedores J2EE que apoyan la especificacion

Capitulo 20
disponible en http://java.sun.com/j2ee/connector/products.htrnl, pero, en este momento, solo la Implementaci6n de Referencia J2EE 1.3 y un par de vendedores J2EE han puesto a disposici6n del pfiblico sus implementaciones beta. Tambikn esti disponible una lista devendedores de EIS que se adaptan a esta arquitectura para proporcionar sus adaptadores de recursos especificos de EIS. Sin embargo, en el momento de publicacion de este libro, ningiin vendedor de EIS ha puesto a disposicih publics sus adaptadores de recursos EIS beta.

Integration de EIS y el roI de JCA


En la era del comercio electronico, las aplicaciones de empresa habilitadas para Internet y la integration de empresas en Internet se han convertido en un hecho fundamental para sus ventajas competitivas. Sin embargo, antes de la aparicidn de la economia de Internet, muchas compafiias y empresas ya habian invertido fuertemente en sistemas de aplicacibn de informaci6n de empresas y gestion, corno:
0 0

Aplicaciones de Planificaci6n de Recursos de Empresa (ERP), como SAP R/3 y BAAN. Aplicaciones de Gestion de Relaciones de Cliente (CRM), como Siebel y Clarify.

O Aplicaciones de bases de datos, como DB2 y Sybase.


0 Aplicaciones de procesamiento de transacciones principales, como CICS.

0 Sistemas de Base de Datos de Legado, como IMS de IBM.

Estos sistemas son denominados generalmente Sistemas de Informaci6n de Empresa, Enterprise Information System (EIS). U n Sistema de Informaci6n de Empresa (EIS) proporciona 10s sewicios e infraestmctura de informaci6n para una empresa. Esta informaci6n puede estar en forma de u n conjunto de registros e n una base de datos, objetos de empresa e n u n ERP, u n objeto de flujo de trabajo en u n sistema de gesti6n de relaciones de cliente (CRM) o u n programa de transacci6n en una aplicaci6n de procesamiento d e transacciones. Incorporar estas complejas aplicaciones de empresa en un sistema de aplicaciones multi-capa supone un reto bastante importante e implementarlas para una aplicaci6n Web de alta disponibilidad es un proyecto colosal. Antes de la Arquitectura de Conectores, algunos vendedores de servidores de aplicacidn proporcionaban o se adaptaban a una variedad de adaptadores personalizados para sistemas EIS integradores. Estos adaptadores proporcionaban bisicamente interfaces nativas personalizadas, que eran complejas de entender y eran restrictivas a1 intentar adaptarse a una arquitectura estindar. Mis concretamente, algunas de estas limitaciones eran las siguientes:
0

La programaci6n de aplicaciones para EIS es de propiedad por naturaleza y la completa variedad de sistemas de aplicaci6n significaba que no existia ningtin mecanismo de interfaz generic0 para la integration de arquitecturas abiertas. nfimero de clientes, gesti6n de conexiones, etc. Tradicionalmente, el ndmero de clientes y sus conexiones activas resultan caras en un EIS y 10s adaptadores personalizados carecen de apoyo para mecanismo de gesti6n de conexiones proporcionados por servidores de aplicaci6n.

O Las aplicaciones Web de gran escala requieren aha disponibilidad y reajustabilidad respecto del

O La gestion de la seguridad y de las transacciones distribuidas con mtiltiples aplicaciones en segundo

plano es extremadamente compleja y carece de mecanismos fiables. Esto significa que no existia

La arquitectura de conectores J2EE


ninguna soluci6n disponible de infraestructura estindar para proporcionar un mecanismo de seguridad neutral en relacidn con el vendedor y apoyo genkrico de gesti6n de transacciones para rnGltiples gestores de recursos EIS. Esto puede plantear importantes problemas con la irnplementaci6n de EAI. Enfrentindose a estos retos, Sun Microsystems ha lanzado la Arquitectura de Conectores J2EE 1.0 para ofrecer una arquitectura estindar para la integraci6n de servidores J2EE con recursos EIS heterogkneos. Su objetivo principal es sirnplificar el proceso de desarrollo para la integraci6n definiendo un API comlin y un conjunto comGn de servicios dentro de un entorno J2EE consistente.

La Arquitectura de Conectores JZEE (JCA) proporciona u n Mcil enfoque para que 10s desarrolladores integren sin fisuras 10s Sistemas de Informaci6n de Empresa (EIS) con componentes de la plataforma JZEE.
El siguiente diagrams muestra la nueva cara de un servidor de aplicacidn J2EE 1.3 con componentes JCA y ejernplo de Sistemas de Informaci6n de Ernpresa potenciales:

[~ontenedor Web

' .

--

-' i

EIS

Por lo tanto. si necesitamos intercrar una adicacibn de base T2EE con un EIS existente. s61o necesitamos instalar el conector EIS apropiado (un adaptador de recursos que se ajuste a JCA) en nuestro servidor de aplicaci6n. Con el adaptador instalado, podemos desarrollar componentes J2EE para que actGen de interfaz utilizando el API de la Interfaz Comb de Cliente (CCI), del mismo modo que podemos utilizar JDBC para que actGe de interfaz con bases de datos relacionales. En otras palabras, se sirnplifica el desarrollo con programaci6n no especifica de EIS y con una configuraci6n completamente independiente del EIS en segundo plano. La idea es que todos 10s vendedores de servidores de aplicaci6n irnplementarin eventualmente servicios JCA y 10s vendedores de EIS irnplementarin adaptadores de recursos de EIS que se ajusten a JCA. Apoyando la Arquitectura de Conectores JZEE, se garantiza que todos 10s servidores de aplicaci6n que se adapten a JZEE manejan rndltiples y heterogineos recursos EIS. Asi, J C A fomenta la productividad de 10s desarrolladores de aplicaciones J2EE paralelamente a la reducci6n de costes de desarrollo y la protecci6n de la inversidn existente en sisternas EIS proporcionando una soluci6n de integracidn reajustable a travks de J2EE.

Capitulo 20

La Arquitectura de Conectores JZEE y sus elementos


JCA es implementado en un servidor de aplicacidn que se ajuste a J2EE 1.3, con un adaptador de recursos JCA proporcionado por un vendedor EIS. Este adaptador de recursos es una componente J2EE conectable, especifico de EIS en el servidor de aplicacidn, que proporciona una interfaz para comunicaciones con el sistema EIS subyacente. Bisicamente, J C A define la siguiente lista de elementos y servicios:
0

Contratos y servicios de nivel de sisterna- Define el estindar entre 10s componentes J2EE, el proveedor del servidor de aplicaci6n y el sistema EIS. Estos contratos y servicios son implementados en el servidor de aplicacidn por el proveedor del servidor y tambiCn en el adaptador de recursos por el vendedor EIS. La implementacidn de contactos y servicios define una separacidn 16gica (no fisica) entre el servidor de aplicacidn y el adaptador de recursos en tirminos de roles y responsabilidades de nivel de sistema. Esto permite la coordinacidn entre el servidor J2EE y a1 adaptador de recursos (por ejemplo, reserva de conexiones, seguridad y transacciones). Ademis, permite que el adaptador de recursos adaptado a JCA sea conectable a cualquier servidor J2EE. La Interfaz C o m u n de Cliente (CCI) JCA- Define un API cliente que utilizan 10s componentes J2EE (como JSP, EJB, etc.) para conectar e interactuar con sistemas EIS. Ademis de 10s componentes cliente J2EE, tambiin permite que las aplicaciones no gestionadas (como applets Java y clientes de aplicaci6n) se integren con un EIS utilizando un adaptador de recursos adaptado a JCA. conectarse a aplicaciones J2EE.

0 Interfaces de ernpaquetado y despliegue- Permiten a 10s diversos adaptadores de recursos EIS

El siguiente diagrama ilustra la arquitectura de conectores J2EE y 10s componentes que acceden a recursos EIS: Contrato de Cornponentes de Contenedor bmponentes

Gestor de Conexlones Gestor de Transacclones


- -

Gestor de Segurldad

Recursos

La arquitectura de conectores J2EE


El adaptador de recursos puede percibirse claramente como el componente fundamental del JCA, ya que sirve como conector central entre 10s componentes JZEE, el servidor de aplicaci6n y el sistema EIS. En un sistema de aplicacion J2EE que utiliza JCA, 10s vendedores de EIS proporcionan adaptadores de recursos que se ajustan a JCA con C C I como parte de su implementaci6n. Los vendedores de servidores J2EE proporcionan servidores de aplicaci6n que apoyan contratos de nivel de sistema que capacitan a estos adaptadores de recursos para conectar con 10s servidores de aplicaci6n y proporcionar conectividad con recursos subyacentes EIS. Esto permite a 10s desarrolladores de aplicacibn J2EE desarrollar componentes de integration utilizando CCI. Por lo tanto, pueden mantenerse alejados de 10s mecanismos de conexion, seguridad y transacciones destinados a la conectividad con un EIS o hiiltiples recursos EIS. La especificacion JCA apoya dos tipos de entornos, basados en el tip0 de aplicaci6n cliente que utiliza el adaptador de recursos:
0 Entorno gestionado Define una aplicacidn de base J2EE, con capacidad Web, multi-nivel que accede a EIS. La aplicacion puede contener uno o mis componentes de aplicacidn (por ejemplo, EJB, piginas JSP, servlets), que se implementan en sus respectivos contenedores. En el contexto de JCA, estas aplicaciones son referidas como aplicaciones gestionadas. 0 Entorno n o gestionado La arquitectura de conectores apoya el acceso a EIS desde clientes como applets o aplicaciones cliente de Java. Habitualmente, un cliente de aplicaci6n utiliza directamente una libreria de adaptadores de recursos en una arquitectura de dos gradas. En este caso, el adaptador de recursos proporciona a sus clientes transacciones y seguridad de nivel inferior. En un contexto JCA, estas aplicaciones son referidas como aplicaciones no gestionadas.

Analizaremos ambos entornos mis adelante, en este mismo capitulo.

Comparacion de JCA con JDBC


En general, JCA y JDBC son tecnologias sirnilares con idhticos mecanismos con respecto de la gesti6n de conexiones y transacciones.
-

Los adaptadores de recursos para sistemas EIS son anilogos a 10s controladores JDBC para bases de datos relacionales. La siguiente tabla presenta una comparaci6n entre JCA y JDBC, y demuestra las similitudes (y diferencias) entre 10s dos:

I
Definicion

JDBC 2.0 Proporciona una interfaz genkrica para interactuar con bases de datos relacionales Define un API Java estandar para acceder a bases de datos relacionales Usa controladores JDBC especificos para RDBMS JCA 1.0 Proporciona una arquitectura estindar para que J2EE y aplicaciones Java integren e interactiien con recursos EIS Utiliza la Interfaz Comiin de Cliente (CCI) paraproporcionar un API independiente de EIS Utiliza un adaptador de recursos EIS para interactuar con un EIS
La tabla continua en la pcigina siguiente

API

Conexion
I

Capitulo 20
JDBC 2.0 Implementaci6n de Servidor Los servidores J2EE im lementan mecanismos de reserva l e conexiones DBC para crear conexiones a una ase de datos Apoya aplicaciones no gestionadas (aplicaciones de dos niveles), que uthzan JDBC Apoyo a la Interfaz de Proveedor de Servicios (SPI) Apoyo de transacc16n Apoyo JTA Proporciona apoyo (desde JDBC 3.0) y relacion con SPI JCA JCA 1.0 Los servidores J2EE implernentan contratos de servicio JCA para establecer una factoria de conexiones y gestionar conexiones con un EIS Apoya aplicaciones no gestlonadas (aplicaciones de dos niveles), que utilizan C C I JCA define SPI para servicios integradores de servidor de aplicaci6n, como transacciones, conexiones y seguridad Apoya transaccionesXA y no-XA con recursos EIS subyacentes Apoyo a JTA con un contrato entre el estor de transacciones J 1 ~gestor ~ de recursos EIS

Apo a transacciones XA y no-XA con ruentes de datos XA rubyacentes Pro orciona una interfaz para el apoyo y JTS a

PA

Asi, desputs de la comparaci6n, la diferencia entre las dos tecnologias esti clara: JDBC proporciona controladores y un API cliente para conexion e integration con aplicaciones de base de datos relacionales, rnientras que JCA proporciona adaptadores de recursos y un API cliente (CCI) para capacitar la integraci6n sin fisuras con recursos EIS.

El adaptador de recursos y sus contratos


El adaptador de recursos contiene una biblioteca especifica EIS (que puede ser escrita en Java o con componentes nativos de interfaz) que proporciona la conectividad a1 EIS que representa. En el servidor de aplicacion J2EE, el adaptador de recursos se ejecuta en el espacio de direcciones del servidor de la aplicacion y gestiona la conectividad a1 EIS subyacente. JCA requiere que todos 10s adaptadores de recursos EIS y servidores de aplicacion J2EE que se ajusten a JCA apoyen 10s contratos de nivel de sisterna. JCA tambitn recomienda (pero no establece obligatoriamente) que todos 10s adaptadores de recursos apoyen C C I como su API cliente. Esto proporciona una soluci6n basada en J2EE para el desarrollo de aplicaciones que integre multiples EIS y permita esa "conectabilidad de adaptadores de recursos EIS en un servidor de apkaci6n, en colaboraci6n con todos 10s mecanismos de nivel de sistema. Segun la especificaci6n JCA, 10s adaptadores implementan generalmente dos tipos principales de contratos, que analizaremos en las siguientes secciones.

En general, un contrato en este context0 es sirnplemente una declaraci6n de responsabilidades entre capas de la aplicaci6n que implementa una interfaz estdndar entre dichaos niveles.

Contratos de aplicacion
Los contratos de aplicacion definen el API de Interfaz C o m h de Cliente (CCI) a travts del cual un componente cliente J2EE (un EJB o un servlet, por ejemplo) o un cliente no gestionado se comunica con 10s recursos EIS subyacentes.

La arquitectura de conectores J2EE


Contratos de nivel de sistema
Los contratos de nivel de sistema definen un conjunto de contratos de sistema, que permiten a1 adaptador de recursos vincularse a 10s servicios del servidor de aplicaci6n para gestionar las conexiones, las transacciones y la seguridad. La especificaci6n JCA define una serie de contratos de nivel de sistema para que el adaptador de recursos y el servidor de aplicaci6n J2EE 10s implementen. Son analizados detenidamente en las siguientes subsecciones.
Gestion de conexiones

La gesti6n de conexiones esti representada por un contrato de servicios que permite a1 servidor de aplicacidn ofrecer sus servicios para crear y gestionar reservas de conexiones con el recurso EIS subyacente. Proporciona una funci6n de gesti6n de conexiones reajustable para apoyar un gran numero de clientes. El contrato de gesti6n de conexiones pretende realizar las siguientes funciones:

O Establecer una prictica consistente de programacidn de aplicaciones para proporcionar la adquisicidn de conexiones tanto para aplicaciones gestionadas (aplicaci6n J2EE) como para aplicaciones no gestionadas (de dos niveles).

o Capacitar a1 adaptador de recursos EIS para proporcionar una factoria de conexiones e interfaces
de conexi6n basadas en la C C I especifica para el tip0 de adaptador de recursos y el EIS.

O Proporcionar un mecanismo genirico para 10s componentes J2EE gestionados por el que un servidor de aplicaci6n J2EE puede ofrecer servicios como transacciones, seguridad, reserva avanzada, seguimiento/registro de errores, etc.

Proporcionar apoyo para reserva de conexiones.

Gestion de transacciones

Este contrato amplia la capacidad transaccional del servidor de aplicaci6n a 10s gestores de recursos EIS. En el context0 de JCA, un gestor de recursos EIS gestiona un conjunto de recursos EIS compartidos para participar en transacciones. U n gestor de recursos puede gestionar dos tipos de transacci6n:
0

Transacci6n XA Estas transacciones estin controladas y coordinadas por gestores externos de transacciones. Son compatibles con contratos de gesti6n de transacciones XAResource con un adaptador de recursos que se ajusta a JCA y su gestor subyacente de recursos EIS. Esto tambiin significa que el recurso EIS participante t a m b i h apoya transacciones XA de base JTA implementando un XAResource a travks de su adaptador de recursos. La interfaz JTA XAResource permite a dos gestores de recursos participar en transacciones coordinadas por un gestor externo de transacciones. Esto permite que la transacci6n sea gestionada por un gestor de transacciones externo a1 adaptador de recursos. Cuando un componente de aplicaci6n J2EE demarca una solicitud de conexi6n EIS como parte de una transacci6n, el servidor de la aplicaci6n es responsable de alistar el recurso XA con el gestor de la transacci6n. Cuando el cliente cierra la conexi6n, el servidor de aplicaci6n retira el recurso XA del gestor de transacciones y, una vez que se ha completado la transacci611, limpia la conexi6n EIS. Esto permite a1 componente de empresa participar en situaciones de realizaci6n en dos fases.

O Transacci6n local Son transacciones gestionadas internamente, es decir, ningun gestor de transacci6n externo implicado. En este caso, las transacciones son demarcadas por el contenedor del servidor J2EE (gestionado por contenedor) o por el componente J2EE (gestionado por componente). Esto permite a1 servidor de aplicaci6n gestionar recursos locales a la aplicaci6n y a su adaptador de

recursos. En las transacciones gestionadas por componentes, 10s componentes J2EE utilizan la interfaz JTA U s e r T r a n s a c t i o n o un API de transacci6n especifico del EIS. Cuando un componente de aplicaci6n solicita una conexi6n EIS, el servidor de aplicacion inicia una transacci6n loca utilizando el contexto de transacci6n disponible en ese momento. Cuando el componente de aplicaci6n cierra la conexihn, el servidor de aplicacion realiza ( o deshace, si es necesario) la transacci6n local y limpia la conexi6n EIS. Estos dos tipos de transacciones permiten a1 gestor de transacciones provisto en el servidor de aplicaci6n gestionar transacciones en mdtiples gestores de recursos EIS.
Gestion de seguridad

Este servicio permite al desarrollador definir la seguridad entre el servidor de aplicaci6n y el recurso EIS. Hay una variedad de mecanismos utilizados para proteger un EIS contra accesos no autorizados y otras amenazas de seguridad, que incluyen:
0 0

Identification de usuario, autentificacibn y autorizaci6n.


Comunicaci6n segura entre el servidor de aplicaci6n y el recurso EIS, utilizando protocolos de seguridad de comunicaci6n de red abierta como Kerberos, que proporcionan seguridad de extremo a extremo con servicios de autentificaci6n y confidencialidad. Activar mecanismos de seguridad especificos de EIS.

Fundamentalmente, el contrato de seguridad entre el servidor J2EE y el adaptador de recursos EIS amplia el contrato de gesti6n de conexiones junto con la seguridad. Este contrato de seguridad proporciona el siguiente mecanismo EIS de acceso:
0

Pasar la solicitud de conexi6n desde el adaptador de recursos al servidor de aplicaci6n J2EE y capacitar a1 servidor con sus servicios de autentificacidn y autorizaci6n. Propagar el contexto de seguridad con credenciales de seguridad desde el servidor de aplicaci6n a1 adaptador de recursos.

Acceso a EIS

En una nueva conexi6n a EIS, crear una conexi6n a EIS crea normalmente un proceso de acceso. Esti basado en el contexto de seguridad, que crea un proceso de autentificacion y autorizaci6n para que un usuario obtenga las reglas de acceso. En cualquier caso, si cambia el contexto de seguridad, se requiere reautentificaci6n para la conexi6n. U n acceso a EIS requiere uno o mis de 10s siguientes pasos:
0

Determinar el principal del recurso (identidad del oyente iniciador) bajo cuyo contexto de seguridad se estableceri una nueva conexi6n a un EIS. Establecer una asociaci6n segura entre el servidor de aplicaci6n y el EIS. T a m b i h pueden desplegarse mecanismos adicionales como SSL o Kerberos. Controlar el acceso a recursos EIS.

0 Autentificar el principal de 10s recursos si la conexi6n a h no esti autentificada. 0 0

Una vez se ha establecido una asociaci6n segura, la conexi6n se asocia al contexto de seguridad del usuario iniciador. Posteriormente, todas las invocaciones de nivel de aplicaci6n a la instancia EIS que utilicen la conexi6n tiene lugar en el contexto de seguridad de ese usuario. JCA recomienda que 10s vendedores de servidores J2EE proporcionen y sean compatibles con el acceso gestionado por contenedor para aplicaciones J2EE gestionadas y acceso gestionado por aplicaci6n para aplicaciones n o gestionadas. Definamos estas dos tkcnicas de acceso:

La arquitectura de conectores J2EE


0 Acceso gestionado por aplicaci6n El componente cliente proporciona las credenciales de seguridad (habitualmente, nombre de usuario y contrasefia) mientras obtiene una conexion a un EIS.

Acceso gestionado por contenedor El componente de cliente J2EE n o presenta ninguna credencial de seguridad y es responsabilidad del contenedor J2EE encontrar las credenciales necesarias de acceso y proporcionarles el adaptador de recursos mientras solicita una conexion a un EIS. En esta situaci6n, el contenedor debe encontrar el principal de recurso (identidad del llamante iniciado) y proporcionar informaci6n sobre este principal de recurso a1 adaptador de recurso en forma de tema de Servicio de Autentificacion y Autorizaci6n Java (JAAS).

Empaquetado e implernentacion de un adaptador de recursos


JCA define 1as interfaces de empaquetado e implementaci6n, de modo que varios adaptadores de recursos pueden conectar ficilmente con un servidor de aplicacion J2EE adaptado de un mod0 modular y portitil. Esto se conoce como modulo de adaptador de Recursos ( . r a r ) y es similar a un m6dulo de aplicaci6n J2EE (. e a r ) , que puede incluir componentes Web y EJB. El siguiente diagrams ilustra 10s pasos del proceso de empaquetado e implementaci6n de un modulo de adaptador de recursos destinado a conectar una aplicaci6n J2EE con un recurso EIS. Habitualmente, este proceso es muy similar a la implementacidn de componentes EJB y Web en un contenedor J2EE.

-Adaptador de Recurso Adaptador de Recutso Recursos b -, Ernpaquetado Procedente de Modulo de Procedente del

- - -- - -

Conf~gurac~on del Entorno Procedente del Desplegador _ __

lncluir M6dulos J2EE

Servidor de Aplicacion J2EE

Contenedor

Adaptador de

I -

Adaptador de Recursos Especif~co de EIS

Asi, el proceso de empaquetado e implementaci6n de un m6dulo de recursos es el siguiente:


0 El proveedor del adaptador de recursos EIS (normalmente, el vendedor de EIS) desarrolla un conjunto de interfaces y clases de utilidad Java como parte de la implernentaci6n del adaptador de

Capitulo 20
recursos. Estas clases Java implementan 10s contratos JCA y la funcionalidad especifica de EIS proporcionada por el adaptador de recursos.
0 Las clases y bibliotecas nativas Java (si estin disponibles) proporcionadas por el proveedor del adaptador de recursos son empaquetadas, junto con un descriptor de implementaci6n, para construir un m6dulo de adaptador de recursos (archivo RAR). Similar a otros descriptores de implementaci6n del componente J2EE, el descriptor del m6dulo del adaptador de recursos define 10s atributos de contrato de servicio entre el proveedor del adaptador de recursos y un implementador para un adaptador de recursos. 0 Durante la implementaci6n, el implementador de la aplicacidn instala un m6dulo del adaptador de recursos en un servidor de aplicaci6n y despuks lo configura con el servidor de aplicaciones J2EE y el entorno subyacente EIS de destino.

Como hemos mencionado anteriormente, el proceso de empaquetado e implementaci6n de un m6dulo de adaptador de recursos para una aplicaci6n es similar a otros procesos de empaquetado e implementaci6n JZEE, especialmente para componentes Web y EJB. Sin embargo, 10s roles y las responsabilidades implicadas en el empaquetado e implementaci6n de un adaptador de recursos son ligeramente diferentes comparadas con otros componentes J2EE.

Empaquetar un adaptador de recursos


U n adaptador de recursos EIS es un componente de servidor J2EE contenido en un archivo RAR. Puede hospedar uno o mis adaptadores de recursos en un directorio y empaquetarlos como archivos . r a r . La siguiente lista de tareas indica la secuencia habitual que conlleva empaquetar un adaptador de recursos:

I. Crear un directorio de hospedaje temporal.


2. Compilar o copiar las clases Java de adaptador de recursos en el directorio de hospedaje.
3. Crear un archivo .r a r para almacenar las clases Java del adaptador de recursos y afiadir este archivo j a r a1 nivel superior del directorio de hospedaje.

4. Crear un s u b d i r e c t o r i o M E ~ ~ INF - en el directorio de hospedaje. 5. Crear un archivo de descriptor de implementaci6n r a .xml en el s u b d i r e c t o r i o ~ INF ~ ~ ~y- afiada entradas para el adaptador de recursos.
6. Crear un descriptor de implementaci6n especifico del vendedor J2EE en el s u b d i r e c t o r i o ~ ~ ~ ~ INF y afiada entradas para el adaptador de recursos.

7. Cuando todas las clases y descriptores de implementaci6n del adaptador de recursos se hacen disponibles en el directorio de hospedaje, puede crear el archivo . r a r del m6dulo del adaptador de recursos con un comando j a r , como kste:
jar c v f wroxResourceAdapter. rar -C staging-dir

Finalmente, podemos implementar este archivo .rar en cualquier servidor J2EE que se ajuste a JCA o empaquetarlo en un archivo . j a r de aplicaci6n. Observe que la opci6n - C s t a g i n g d i r define el comando j a r para cambiar el directorio s t a g i n g - d i r de mod0 que las rutas de directorio definidas en el archivo rar sean relativas a1 directorio donde ha hospedado 10s adaptadores de recursos. U n mddulo de adaptador de recursos empaquetado define el contrato entre un proveedor y un ' implementador de adaptador de recursos EIS, e incluye 10s siguientes elementos:

La arquitectura de conectores J2EE


O

Las clases e interfaces Java requeridas para la implementaci6n de 10s contratos de arquitectura de conectores y de la funcionalidad del adaptador de recursos.

o Las clases de utilidad Java para el adaptador de recursos.


O

Librerias nativas dependientes de la plataforma requeridas por el adaptador de recursos

O Archivos de ayuda y documentaci6n.

Meta-informaci6n descriptiva que vincula a 10s elementos anteriores. El proceso de implementacidn empieza con el archivo .rar o con un directorio de implementaci6n, ambos contienen las interfaces y las clases de implementaci6n del adaptador de recursos compiladas proporcionadas por el proveedor del adaptador de recursos. Los adaptadores de recursos en una entorno J2EE utilizan un formato comb de directorio. U n adaptador de recursos esti estructurado en un directorio como se muestra en el siguiente ejemplo:
\J2EEserverHome \config \wroxdnrns i n \applicstioris \wroxResourceAdapter \imaqrs \ra. jpg \ rsadrnz. htrnl \els .jar \utilities. j ar \windos.dl; \solaris. s n \META-INF \ r a .xml \XYZServerFrnvider-ra. xrnl

Este mismo formato puede utilizarse a1 empaquetar un adaptador de recursos como archivo . rar. Despues de crear un archivo .rar,su instalacion de servidor J2EE queda asi:

En la estructura anterior, ra .xml es el descriptor de despliegue para el adaptador de recursos. XZYServerProvider- ra .xml es el descriptor de despliegue delvendedor J2EE, que definelos parimetros operativos exclusivos del proveedor del servidor. Examinaremos mis detalladamente el descriptor en la pr6xima secci6n. ei s . ja r y utilities .j ar contienen interfaces y clases de implementaci6n Java del adaptador de recursos EIS. Los archivos windos .dl1 y solaris. s o son ejemplos de librerias nativas.

El descriptor de implernentacion del adaptador de recursos (ra .xml)


Similar a otras aplicaciones J2EE, 10s adaptadores de recursos EIS tambien utilizan descriptores para definir el contrato entre un proveedor de adaptador de recursos EIS y un implementador de este entorno. ~ s t o proporcionan s 10s atributos destinados a que el implementador permita la implementaci6n de un adaptador de recursos EIS en su entorno. El vendedor J2EE tambien requiere un descriptor adicional, que defina 10s parametros operativos exclusivos del proveedor del servidor.

Capitulo 20
U n modulo de adaptador de recursos tambiCn inchye 10s requisitos de implementacion especificados por el proveedor del adaptador de recursos en el descriptor. Para configurar las propiedades de implementacion necesarias para el adaptador de recursos, es necesario editar el archivo r a . xml empaquetado con un adaptador de recursos. La definition del tip0 de documento XML del descriptor para un modulo de adaptador de recursos esta disponible en http://java.sun.com/dtd/connector~l~O.dtd. El proveedor de adaptador de recursos es responsable de proporcionar el descriptor de implementaci6n para un adaptador de recursos especifico de EIS. C o m o sucede con JCA 1.0, la siguiente informacion esta disponible en un descriptor provisto por un proveedor de adaptador de recursos EIS:
0

Informaci6n general sobre un adaptador de recursos. Como vemos en el siguiente extract0 de codigo, esta informacion puede incluir detalles como el nombre del adaptador de recursos, el nombre del vendedor que proporcionar el adaptador de recursos, el tip0 de sistema EIS en que se basa, la version del JCA en que se basa, etc. Por ejemplo:

La c l a s e ~ a n a ~ e d ~ o n n e c t i o n ~ a el ct proveedor or~; del adaptador de recursos especifica el nombre cualificado completo de la clase Java que implementa la interfaz javax.resource.spi.ManagedConnectionFactory.~ore~emplo:

La interfaz y clase de i m p ~ e m e n t a c i o n ~ o n n e c t i o n ~ a c t oel ry proveedor ; del adaptador de recursos especifica el nombre cualificado complete de la interfaz y clase de implementaci6n Java para la factoria de conexiones. Por ejemplo:

<conntctior~factory-ir~terf ace> ]avax.sql.DataSource </connectionfactory-interface>


<conr~ectior~factory-1rnp1-c1ass>

corn. sun. connector. blackbox. JdbcDataSource </connectionfactory-impl-class>

Clase de implementacion de la conexion; el proveedor del adaptador de recursos especifica el nombre completo cualificado de la clase de implementaci6n para la interfaz de conexion:

U Apoyo transaccional; el proveedor del adaptador de recursos especifica el nivel de compatibilidad de transaccion proporcionado por la implementaci6n del adaptador de recursos. El nivel de compatibilidad transaccional es normalmente uno de 10s siguientes: N o T r a n s a c t i o n , LocalTransactionoXATransaction.~orejemplo:

Propiedades configurables de l a i n s t a n c i a ~ a n a ~ e d ~ o n n e c t i o n ~ a c t eloproveedor r~; del adaptador de recursos define nombre, tipo, description y valores predeterminados opcionales para las propiedades que han sido configuradas para cada instancia d e ~ a n a g e d ~ o n n ei c ot n ~ a cotr y

La arquitectura de conectores J2EE


(observe que estamos utilizando la base de datos por defect0 Cloudscape, C l o u d s c a p e D B , en este ejemplo):

Mecanismo de autentificacion; el proveedor del adaptador de recursos especifica todos 10s mecanismos de autentificacion apoyados por el adaptador de recursos. Incluye el apoyo proporcionado por la implementacion del adaptador de recursos pero no la instancia subyacente EIS. Los valores estindar son B a s i c P a s s w o r d y Kerbv5, por ejemplo:
<authentication-mechanism> <authentication-mechanism-type> BasicPassword </authentication-mechanism-type> <credential-interface> javax.resource.security.PasswordCreder~tia1 </credential-interface> </authentication-mechanism> 0

Apoyo de reautentificacion; el proveedor del adaptador de recursos especifica si su adaptador de ' recursos apoya la reautentificacion de una conexion existente:

El siguiente ejemplo ilustra un descriptor de implementacion completo para un adaptador de recursos de caja negra, sin apoyo de transacci6n (incluido en el archivo . r a r ) :
<?xml version="l. 0" encoding="UTF-B"?> < ! DOCTYPE cor~nector PUBLIC '-//Sun Microsystems, Inc. //DTD Connector 1.0/ /EN' 'http: //j ava. s u n . corn/ j2ee/dtds/connector 1 O . d t d l >

<resourceadapter> <managedconnectionfactoryclass> com. sun. connector. blackbox . N o T x M a r ~ a g e d C o r ~ r ~ e c t i o r ~ F a c t o r y </managedconr~ectionfactory-class>


<conr~ectionfactory-interface>

javax.sql.DataSource</connectior~factory-ir~terace> <connectionfactory-impl-class> com.sun.cor~r~ector.blackbox.JdbcDataSource </connectionf actory-impl-class> <connection-interface>j ava. sql . C o n r ~ e c t i o r ~ < / c o n r i e c t i o r ~ - i n t e r f a c e > <cor,nectior~-impl-class> com. sun. connector. blackbox. JdbcConnection </cor~r~ectiori-impl-class> <trar~sactior~-support>N~Tra~i~a~tior~</trar~sactior~-support> con fig-property>

Capitulo 20
<conf iq-property-name>Connect ionURL</config-property-name> <conf iq-property-type>j ava. lar~q. Strlnq</config-property-type> <config-property-value> jdbc:cloudscape:rmi:CloudscapeDB;create=true </config-property-value> </conf iq-property> <authentication-mechanism>
<authentication-mechar~ism-type>

BasicPasswqrd </authentication-mechanism-type> <credential-interface> javax.resource.security.PasswordCredentia1 </credential-interface> </authentication-mechanism>


<reauthent~catior~-support>fa1se</reauthenticatior1-support>

</resourceadapter>

Roles y responsabilidades de la irnplementacion


Los roles y responsabilidades especificas de la implementaci6n son 10s siguientes:

Proveedor del adaptador de recursos


El proveedor del adaptador de recursos, como el nombre sugiere, es responsable de proporcionar un adaptador de recursos para un EIS. U n vendedor EIS o su vendedor de terceros proporciona habitualmente el adaptador de recursos y su sistema de herramientas de implementaci6n de la aplicaci6n. T a m b i h es responsable de especificar el descriptor para su adaptador de recursos, que incluye:
0

Informacidn general: detalles generales del adaptador de recursos (nombre, descripci6n, nombre de vendedor, licencia, apoyo EIS, version, etc.). La c l a s e ~ a n a g e d ~ o n n ei cot n ~ a cotr y : especifica el nombre cualificado completo de la clase Javaque implementalainterfaz ja v a x .r e s o u r c e . s p i . M a n a g e d C o n n e c t i o n F a c t o r y . La interfaz y clase de i m p l e m e n t a c i 6 n ~ o n n e c t i o n ~ a c t o respecifica y: el nombre completo cualificado de la interfaz y clase de implementacion Java para la factoria de conexiones. implementaci6n del adaptador de recursos ( N o T r a n s a c t i o n , L o c a l T r a n s a c t i o n o XATransaction).

ad especifica el nivel de apoyo de transacci6n proporcionado por la o C ~ m ~ a t i b i l i d transaccional:

Mecanismo de autentificacibn: especifica 10s mecanismos de autentificaci6n en 10s que se basa el adaptador de recursos. Incluye el apoyo d e ~ a s i c ~ u t h e n t i c a t i y oK n e r b e r o s v5.

Vendedor del sewidor de aplicacion


El vendedor del servidor de aplicaci6n proporciona la implementaci6n JCA en su servidor de aplicaci6n J2EE, que apoya las aplicaciones basadas en componentes JCA. T a m b i h se conoce como proveedor del contenedor, aisla 10s componentes de aplicaci6n J2EE de 10s servicios de nivel de sistema subyacentes.

Proveedor del componente de aplicacion


El proveedor del componente de aplicaci6n desarrolla el componente de aplicaci6n J2EE que interactlia con 10s EIS para proporcionar funcionalidad a la aplicaci6n. El proveedor desarrolla programas utilizando

La arquitectura de conectores J2EE


la CCI, pero no programa especificamente las transacciones, la seguridad, la concurrencia y la

distribution. En su lugar, utiliza el sewidor J2EE para proveer estos sewicios.


lnplementador
El implementador es responsable de configurar un adaptador de recursos en el entorno J2EE de destino. La configuraci6n de un adaptador de recursos esti basada en 10s atributos definidos en el descriptor de implementaci6n como parte del modulo del adaptador que incluye las siguientes tareas:

O Configurar la propiedad establecida porManagedConnectionFactory para crear conexiones a varias instancias EIS subyacentes. O Configurar el senidor de aplicacion para la gestion de transacciones basindose en el nivel de compatibilidad de transaction especificado por el adaptador de recursos. O Configurar la seguridad en el entorno operativo basindose en 10s requisitos de seguridad especificados por el adaptador de recursos en su descriptor de implementacion.

Opciones de implementacion
U n adaptador de recursos puede implementarse de las siguientes formas en una Implementaci6n de Referencia JZEE:

O Dinimicamente, utilizando la linea de comando deploytool (o la consola U I de la herramienta de implementaci6n), por ejemplo:
deploytool -deployConnector %J2EE~HOME%\lib\connector\blackbox-tx.rar localhost

O C o m o parte de una Aplicaci6n de Empresa JZEE, implementindolo como un fichero de archivo llamado .ear. Analizaremos mis detenidamente esta opci6n en la siguiente seccibn.

lmplementar un adaptador de recursos como una aplicaci6n J2EE Como hemos visto, J C A tambikn especifica la posibilidad de i n c h un archivo de fichero ( .rar) del
adaptador de recursos en un archivo de la aplicaci6n de empresa ( .ear) e implementar despuks la aplicacion en un sewidor JZEE. Las siguientes tareas estin implicadas en la implementacidn de una aplicacion J2EE que contiene un archivo del adaptador de recursos:

O Incluir el archivo . rar en el fichero . ear igual que incluiria un archivo .war (componente Web) o .j ar (componente EJB). O Crear un archivo vilido application. xml y situarlo en el directorio META-INF del fichero .ear. Al crear un appl icat ion. xml,asegurese de que el descriptor de implementaci6n de la aplicaci6n contiene un nuevo elemento <connect or> para identificar el archivo del adaptador de recursos en el fichero .ear. Por ejemplo:

Hasta el momento, hemos analizado 10s adaptadores de recursos, 10s contratos de adaptadores de recursos y 10s procedimientos de empaquetado e implementaci6n de un adaptador de recursos. Demostremos ahora la configuraci6n e implementaci6n de un adaptador de recursos utilizando 10s adaptadores de recursos de caja negra provistos por la implementaci6n de referencia J2EE 1.3 de Sun.

Capitulo 20
En el momento de publicacio'n de este libro, 10s adaptadores de recursos EIS apenas estaban disponibles ni siquiera corno una implementacio'n beta. Por ello, en nuestros ejemplos, estamos utilizando 10s adaptadores de recursos de caja negra provistos en la Implementacio'n de Referencia JZEE, que estdn destinados a poner a prueba el proceso de empaquetado e implementacio'n y la C C I . Los adaptadores de caja negra no estdn diseriados para aplicaciones de produccidn.

Adaptadores de recursos de caja negra


Los adaptadores de caja negra son iguales que 10s adaptadores de recursos EIS per0 utilizan una base de datos relational corno EIS subyacente y estin diseriados hicamente para fines de prueba. Sin embargo, son ideales para el prop6sito de nuestras sencillas dernostraciones. Los adaptadores de recursos de caja negra se utilizan principalmente para probar la conectividad de extremo a extremo con un servidor de aplicaci6n J2EE adaptado a JCA y su compatibilidad J2EE segGn la especificacion JCA 1.0. en esta seccibn, exarninaremos el uso de 10s adaptadores de recursos de caja negra integrados en la Implernentaci6n de Referencia J2EE 1.3 de Sun. Estas cajas negras utilizan llarnadas JDBC para interactuar con un DBMS.

Los adaptadores de recursos de caja negra no estiin destinados a sustituir a JDBC; simplemente proporcionan un sencillo entorno sirnulado con fines de prueba unicamente.
Los ejernplos que analizarernos en este capitulo utilizan el servidor de la Irnplernentacion de Referencia J2EE 1.3 y Cloudscape corno base de datos.

Utilizar un adaptador de caja negra. El ejemplo DemoConnector


DemoConnector es un ejemplo que rnuestra un adaptador de recursos de caja negra accediendo a una base de datos Cloudscape utilizando JDBC. El ejemplo es una entidad EJB que realiza transacciones utilizando el adaptador de caja negra configurado con una base de datos y presenta la salida.

Analizarernos el ejernplo Democonnector en el siguiente orden:


0 Selecci6n de un adaptador de caja negra y el nivel de transacci6n de la Irnplementaci6n de

Referencia J2EE
O

Configuraci6n e implernentaci6n del adaptador de caja n e g a Prueba del adaptador de caja negra en una transacci6n utilizando un bean de entidad

Seleccionar un adaptador de caja negra


Examinernos 10s adaptadores de caja negra disponibles en la Irnplernentaci6n de Referencia J2EE 1.3. prirnero, debemos asegurarnos que nuestra instalacidn incluye adaptadores de recursos de caja negra. Norrnalrnente, estin localizados en el directorio % J2EE-HOME% \lib\connector \. Debernos tener cinco adaptadores de recursos de caja negra (identificados por su extensi6n .rar) para apoyar diferentes niveles de transacci6n, corno hernos visto anteriorrnente, en la secci6n sobre gesti6n de transacciones de adaptadores de recursos. Estos adaptadores estin descritos en la siguiente tabla:

La arquitectura de conectores J2EE


Adaptador de recursos de caja negra Descripci6n Para apoyarNO-TRANSACT I O N Para apoyarLOCAL-TRANSACT I O N Para apoyarXA-TRANSACT I O N Implementado con C C I para apoyar LOCAL-TF7ANSACTION Implementado con C C I para apoyar XA-TRANSACTION En nuestro ejemplo, utilizaremos el adaptador de recursos b l a c k b o x - t x . r a r para demostrar el uso de transacciones locales. Transaccioner X A y no-XA que utilizan un adaptador de caja negra Todos 10s adaptadores de recursos de caja negra requieren un URL para crear factorias de conexiones con EIS subyacentes. Estos adaptadores de recursos de caja negra utilizan generalmente drivers JDBC para conectar con la base de datos. Para recursos transaccionales no-XA, es necesario que configuremos la propiedad c o n n e c t i onURL, mientras que para recursos XA, es necesario configurar la propiedad XADataSource. En este ejemplo, utilizaremos el sewidor de la base de datos Cloudscape en la Implementacidn de Referencia J2EE; 10s valores por defect0 proporcionados en el descriptor de implementacibn de un adaptador de caja negra son 10s siguientes:
0

1
(

I b l a c k b o x - t x .r a r

blackbox-notx. r a r blackbox-xa. r a r

Para adaptadores de caja negra no-XA (que utilizan niveles de transaccibn no-XA):

Para adaptadores de caja negra XA (que utilizan niveles de transaccihn XA):


XADataSource
=

jdbc/XACloudscape-xa

Implementation del adaptador de recursos de caja negra


Para configurar e implementar un adaptador de recursos de caja negra, siga estos pasos:

O Configurar su base de datos y drivers JDBC, y crear sus tablas especificas de aplicacibn
0 Implementar su mbdulo empaquetado de adaptador de recursos de caja negra

Configurar la base de d a t a y la tabla Demoaccount Para implementar y poner a prueba el adaptador de recursos de caja negra mencionado anteriormente, utilizaremos la base de datos Cloudscape de la Implementacibn de Referencia J2EE 1.3. Para crear la tabla, inicie el sistema Cloudscape (con el c o m a n d o ~ l o u d s c a p e - s t a r tdesde el directorio %J2EE-HOME% \ b i n ) y ejecute entonces el siguiente SQL:
CREATE TABLE demoaccount
(

VARCHAR(3) CONSTRAINT Demoaccount pk PRIMARY KEY, firstname VARCHAR(25), lastname VARCHAR(251, balance DECIMAL(12,2)

accountid

);

Capitulo 20
Puede ejecutar este S Q L utilizando C l o u d v i m o guardar el SQL en un archivo de texto y ejecutarlo desde la invitacidn a mandato con c l o u d s c a p e - i s 9 1 c r e a te-demoa c c o u n t - t a b l e . sql
Ya estamos preparados con la configuraci6n de la base de datos.

Implementation del adaptador de recurooo


Primero necesitamos iniciar el senidor JZEE, utilizando j 2 e e -verbose, con el que seguro ya esti familiarizado. Una vez se esti ejecutando el senidor, podemos implementar el adaptador de caja negra utilizando la herramienta de implementaci6n. Primero crearemos una nueva aplicacidn para nuestro

Application File N a n : c:\WroxZProJavaSe1venCh20\81ackbo~BIackbo~.ear

( 1 ~rowse,. I

I ApplicationDisplayName:
I
QK

II

cancel

II

Help

... I

Seleccione entonces Add to (Agregar a) I Resource-adapter RAR (Adaptador de recursos RAR) del men6 File (Archivo):

La arquitectura de conectores J2EE

Ile NamP
IavaS@n.er~Ch?bRlachboylB!~chbOx ear

Appllcmort DISIIIW Name: Coraenls: MNIFEST MF

~ppltcallon xml M-12ee-n xml

Desde el cuadro de diilogo abierto, navegue hasta donde e s t i n localizados 10s archivos RAR ( B J 2 E E-H O M E # \ l i b \ c o n n e c t o r ) y seleccioneel a r c h i v o b l a c k b o x - t x . r a r , y aiiidaloa la aplicaci6n:

file

*IS

9 UFIIP;
Q

iampGqm p 1 p p q E qF -F l J fl'Ej@1p J
--

Help

~ ~ S ~ J P C I I ~ ~ AF j ) Ip~ l~ Pl r Sl ~ o ~ Filackbox ?b AlackRo~Lo nlTx ~

flApplications
9 0 Blackbox

1 1 6 & l ~ f l w ~

+ I GF*~ )

9 @ Sewers

fi BIackBowLocalTx
Managed Cnclnscllon raclory.

f l localhost

Version ~ m m a t m

...

Puede ver en el cuadro de didogo General que la factoria de conexi6n para este adaptador de recursos es, de hecho,simplementeun j avax. sql .Datasource. Para desplegar el adaptador, seleccione la aplicaci6n Blackbox y utilice la opcion Deploy (Implementar) del mend Tools (Herramientas):

La arquitectura de conectores J2EE

contacted sewer ... Application Blackbox transferred Blackbox has 0 ejbs, 0 web componenls lo deploy Deploying Ejbs .. Processing beans ... Making client JARS Makinp sewer JARS ... Deployment of Blackbox is complete.

...

Amplie el n o d o Servers (Servidores) de m o d 0 que pueda ver el servidor adjunto de la Implementaci6n de Referencia; selecci6nelo. En la ventana de la parte derecha cambie a1 panel Resource-adapters:

Pulse el b o t h New (Nuevo) para afiadir una nueva factoria de conexi6n. Verl que el adaptador b l a c k b o x - t x . r a r ya estl seleccionado; lo 6nico que tenemos que aiiadir es el JNDl Name ( e i s / WroxEIS, en este caso):

omection Factow JNDl Name:


I

Configur&ion Properties

Recovery Settings -I User Name:


I
1

Observe que la propiedad ConnectionURL estd apuntando a una base de datos Cloudscape. Obviamente, el valor de esta propiedad necesitaria ser modificado si utilizamos una base de datos diferente.
Pulse el bot6n OK (Aceptar) y, si todo ha funcionado, obtendrl una invitaci6n de confirmaci6n:

El panel Resource-adaptersdebe aparecer ask

lo66

La arquitectura de conectores J2EE

Ya estamos preparados para crear el bean de entidad y poner a prueba este adaptador.

Poner a prueba el adaptador de recursos de caja negra


El ejemplo Democonnector es un bean de entidad y sencillo cliente que utiliza el adaptador de recursos de caja negra para tramitar con una base de datos Cloudscape. Presentaremos ahora el c6digo fuente para el EJB.

Observe que todo el cddigo fuente para 10s ejemplos que se muestra en este capitulo (y el resto de ejemplos de este libro) estrin disponibles para su descarga en http://www.wrox.coml

import import import

java.uti1 .Collection; java.rmi.RemoteException; javax.ejb.*;

p u b l i c i n t e r f a c e DemoAccountHorne e x t e n d s E J B H o m e public DemoAccount c r e a t e ( S t r i n g accountid, S t r i n g firstName, String lastNarne, double balance) t h r o w s RemoteException, CreateException; findByPrimaryKey(String accountid)

public DemoAccount

Capitulo 20
throws FinderException, RemoteException; public Collection findByLastName(String lastNarne) throws FinderException, RemoteException; public Collection findInRange(doub1e low, double high) throws FinderException, RemoteException;

La interfaz remota
import j avax .ejb. EJBObject; i m p o r t java.rmi.RemoteException; public interface DemoAccount extends EJBObject
(

public void debit (double amount) throws ProcessingException, RemoteException; public void creditidouble amount) throws RemoteException; public String getFirstName ( ) throws RemoteException; public String g e t L a s t N a m e 0 throws RemoteException; public d o u b l e getBalance ( ) throws RemoteException;
1

La clase de implementaci6ndel bean


import import import import import java. sql. + ; javax. sql. + ; java.util.*; j avax. e j b . + ; j avax. naming. + ;
{

public class DemoAccountBean implements EntityBean private private private private private private private

String accountid; String firstName; String lastName; double balance; EntityContext context; Connection con; String elsName = "java:comp/env/eis/WroxEIS";

public void debit (double amount) throws ProcessingException 1 if (balance - amount < 0) { throw n e w ProcessingException ( ) ;

1
balance
-=

amount;

\
public void credit(doub1e amount) { balance += amount;
)

public String g e t F i r s t N a m e 0 return firstName;

I
public String g e t L a s t N a m e 0 return 1astName;
{

I
public double getRalance() ( return balance; 1

La arquitectura de conectores J2EE


public Strir~g ejbCreate(Strir1g accountid, String firstName, String lastName, double balance) throws CreateException { if (balance < 0.00) [ throw n e w CreateException ("Negative balance not permitted. " )

I
try { insertRow(accountid, firstName, lastName, b a l a n c e ) ; ) catch (Exception e x ) { t h r o w n e w EJBException ("ejbCreate: " t ex.getMessage
1

( ) ) ;

this. accountid = accountid; this.firstName = firstName; this.lastName = lastNarne; this.balance = balance; return accountid;

I
public String ejbFindByPrimaryKeyiString prirnaryKey) throws FinderException { boolean result; try 1 result = selectByPrimaryKey(primaryKey); 1 catch (Exception e x ) { t h r o w n e w EJBExceptior~("ejbFindByPrimaryKey: " t ex.getMessage());
\

if
]

(result) { return primaryKey; else [ t h r o w n e w ObjectNotFoundException("Account Id " t primaryKey " not found. " ) ;

public Collection ejbFindByLastName(String lastName) throws FinderException { C o l l e c t i o n result; try 1 result = selectByLastName(1astName); ] catch (Exception e x ) { t h r o w n e w EJBException ( " e jbFindByLastNarne " + ex. getMessage

( ) ) ;

I
return result;

I
publlc Collection ejbFindInRange(doub1e low, double high) throws FinderExceptior~ { C o l l e c t i o n result; try I result = selectInKange ( l o w , high) ; I catch (Exception ex) { t h r o w n e w EJBException ( "ejbFindIr1Range: " t ex. getMessage (

) ) ;

I
return result;
\

public void e j b R e m o v e 0 { try 1 deleteRow(accountid); ) catch (Exception ex) 1 t h r o w n e w EJBException ("ejbRemove: " t

ex. getMessage

( ) ) ;

Capitulo 20

public void setEntityContext(EntityContext context) [ this. context = context; try I makeConnection0; 1 catch (Exception ex) I throw new EJBException("database failure " + ex.getMessage());

1
\

public void unsetEntityContext() I try I con. close ( ) ; ) catch (SQLException e x ) I throw new E J B E x c e p t i o n ( " u n s e t E n t i t y C o n t e x t :
1

"

ex.getMessage());

public void ejbActivate ( ) [ accountid = (String) context .getPrimaryKey( ) ;

1
public void ejbpassivate ( ) accountid = null;

public void e j b L o a d 0 I try I loadRow( ) ; ) catch (Exception ex) I throw new EJBException("ejbLoad: " ex.getMessage0 ) ;

I
public void ejbStore0 try

I
"

storeRow( ) ; ) catch (Exception ex) i throw new EJBException ("ej bStore: ex.getMessage0 1;

1
public void ejbPostCreate(String accountid, String firstNarne, String lastNarne, double balance) I ) private void makeconnection() throws Narnir~gException, SQLException InitialContext ic = new Initialcontext ( ) ; DataSource ds = (DataSource) ic.lookup(eisNarne); corl = ds. getconnection ( ) ;
)

private void insertRow (String accountid, String firstNarne, String lastNarne, double balance) throws SQLException I String insertstatement
=

La arquitectura de conectores J2EE


"INSERT INTO demoaccount VALUES ( ? , ? PreparedStatement prepStmt = con.prepareStatement(ir1sertStatement); prepstmt. setString (1, prepStmt. setstring (2, prepStmt.setStringi3, prepStmt.setDouble(4, accountid) ; f irstName) ; 1astName); balance);

)";

private void deleteRow(String accountid) throws SQLException String deletestatement = "DELETE FROM demoaccount WHERE accountid PreparedStatement prepStmt = con.prepareStatement(de1eteStatement);

";

private boolean selectByPrimaryKeyiString throws SQLException {

primaryKey)

String selectStatement = "SELECT accountid " t "FROM demoaccount WHERE accountid = ? "; PreparedStatement prepStmt = con.prepareStatement(se1ectStatement); prepStmt.setString(1, primaryKey); ResultSet rs = prepStmt.executeQuery(); boolean result = rs.next ( ) ; prepStmt.close(); return result; private Collection selectByLastName(String throws SQLException { lastName)

String selectstatement = "SELECT accountid " + "FROM demoaccount WHERE lastname = ? "; PreparedStatement prepstint = con.prepareStatement(se1ectStatement); prepStmt.setString(1, lastName); ResultSet rs = prepStmt . executeQuery ( ArrayList a1 = new ArrayList( ) ;
) ;

while (rs.next ( 1 ) [ String accountid = rs.getString(1); al. add ( accountid) ;

1
prepStmt . close ( return al;
}
) ;

private Collection selectInRange(doub1e throws SQLException {

low, double high)

String selectstatement = "SELECT accountid FROM demoaccount " t "WHERE balance BETWEEN ? and ? " ; PreparedStatement prepStmt = con.prepareStatement(se1ectStatement); prepStmt.setDouble(1, low); prepStmt.setDouble(2, high); ResultSet rs = prepStmt.executeQuery(); ArrayList a1 = new ArrayList ( ) ; while (rs.next()) [ String accountid = rs.getString(1); al.add(accountid);

I
prepStmt.close0; return al; I private void loadRow( ) throws SQLException {

String selectstatement = "SELECT firstname, lastname, balance " t "FROM demoaccount WHERE accountid = ? " ; PreparedStatement prepStmt = con.prepareStatement(se1ectStatement);

ResultSet

rs

prepStmt.executeQuery0;

if (rs.next()) { this.firstName = rs.getString(1); this. lastName = rs.getStrinq(2) ; this.balance = rs.getDouble(3); prepStrnt.close();

else I prepstmt. close ( ) ; throw new NoSuchEntityException("Account " " not found");

accountid t

I
private void storeRow() throws SQLException { String updatestatement = "UPDATE demoaccount SET firstname = . "lastname = ? , balance = ? " t "WHERE accountid = ?"; PreparedStatement prepStmt = con.prepareStatement(updateStaternent); prepStmt.setString(1, prepStrnt.setString(2, prepStmt.setDouble(3, prepStmt.setString(4, firstName); 1astName); balance); accountid);

," +

La arquitectura de conectores J2EE


int rowCount = prepstrnt. executeupdate prepStrnt.close0;
( ) ;

if (rowcount == 0 ) [ throw new EJBException("Account update"

accountid

" failed.");

I I

public class Processir~gException extends Exception public ProcessingException (


)

1
[

public ProcessingException (String rnsg ) superirnsg);

I
El dercriptor de implementation EJB
<?xrnl version="l. 0" encoding="UTF-8"?>
< ! DOCTYPE

ejb-j ar PUBLIC '-//Sun Microsysterns, Inc. //DTD Enterprise JavaBeans 2.0//EN1 'http://java.sun.corn/dtd/ejb-jar 2 O.dtdl>

lmplementacion del bean

Compile 10s diversos archivos j ava y Cree el archivo JAR EJB. Despuks, con nuestra apkaci6n Blackbox seleccionada en la herrarnienta de implementaci6n, afiada a la aplicaci6n el archivo JAR que acaba de crear:

Capitulo 20

9i YF I I P ~
9

d Applications 9 0 Wackbox

9 @ DemoAccount
8 DemoAccount

fi BlackBoxLocalTx

Ref Type -resource

Referenced Bv DemoAccount

Reference Name I JNDI Name 1 e~sNdroxElS e ~ s M l r c ~I5 xf - 1

A continuacidn, necesitamos proporcionar a la aplicacidn 10s nombres JNDI mostrados anteriormente y,


finalmente, implementar la aplicaci6n Blackbox en el servidor ejecutado, recordando crear el archivo

JAR del cliente.


El cliente

Este es el cddigo del cliente:


import import import import public j a v a .util.*; javax.naming.Context; j a v a x .naming.InitialContext; j a v a x . rmi. P o r t a b l e R e m o t e O b j e c t ;
class D e m o A c c o u n t C l i e n t
{
[

public static void main(Strinq[] args)


try (

Context i n i t i a l = n e w InitialContext ( ) ; O b j e c t o b j ref = initial. l o o k u p ( "DemoAccount')

DemoAccountHome home = (DemoAccnuntHome) Portab1eRemoteObject.narrow(objre,

La arquitectura de conectores J2EE

DemoAccount ramesh = home.create("lOO", "Ramesh", "Roger", 0.00); ramesh.credit(50.00); ramesh.debit(l0.15); double balance = ramesh.getBalance(); System.out.println("Account Balance = " + String.valueOf(balance) ) ; ramesh.remove( ) ; DemoAccount craig = home.create("200", "Craig", "Berry", 0.00); craig.credit(100.59);
; DemoAccount nikki = home. f indByPrimaryKey ("200") nikki.debit (2.00); balance = nikki.getBalance();

System.out.println("Account Balance = " + String.valueOf(balance)); DemoAccount bill = home.create("300", "Bill", "Clinton", 0.00); bill.credit(2000.00);

DemoAccount bob = home .create ("400", "Bob", "Clinton", 0.00) ; bob.credit (1000.00); DemoAccount jim = home.create("500", "Jimmy", "Clinton", 0.00); jim.credit(1000.00); Collection c = home. findByLastName ("Clintonn') ; Iterator i=c.iterator(); while (i. hasNext ( ) ) { DemoAccount account = (DemoAccount)i.next(); String accountid = ( S t r i n g ) a c c o u n t . g e t P r i m a r y K e y ( ) ; double amount = account.getBalance( ) ; System.out.println(accountid + ": " + String.valueOf(amount));

while (i.hasNext ( ) ) { DemoAccount account = (DemoAccount)i.next(); String accountid = ( S t r i n g ) a c c o u n t . g e t P r i m a r y K e y ( ) ; double amount = account.getBalance0; System.out.println(accountid + " : " + String.valueOf(amount) ) ;
\

catch (ProcessingException ex) { System.err.println("Caught an ProcessingException: + ex.getMessage ( ) ) ;


);

"

catch (Exception ex) { System.err.printlr1 ("Caught an exception." ex.printStackTrace0;

I
1
Finalmente, ejecute ~ e m o ~ c c o uC nl ti e n t , desde una ventana de comando, recordando incluir el archivo B l a c k b o x c l i e n t . j a r en su ruta de clase. El cliente debe mostrar 10s siguientes resultados en su ventana de comandos:

Capitulo 20

La lnterfaz Comun de Cliente (CCI)


La Interfaz Comdn de Cliente (CCI) proporciona un enfoque sencillo para el problema de escribir una interfaz Jnva mis compleja para un recurso EIS subyacente. Hasta la aparici6n de CCI, este problema ha sido una cuesti6n entre desarrolladores Java y vendedores EIS conocida com~inmente como "caos de integraci6nW. Implementando C C I en adaptadores de recursos, 10s vendedores EIS pueden proporcionar una interfaz Java a sus productos EIS que se ejecutadn en cualquier servidor de aplicacion que se ajuste a J2EE 1.3. La C C I define un API cliente independiente de EIS para componentes de aplicaci6n J2EE que permite que tales componentes se integren e interactien en recursos EIS heterogheos. Define las interfaces de llamada de funci6n remota para ejecutar consultas y transacciones con un EIS y obtener asimismo 10s resultados. Bisicamente, C C I proporciona API de llamada de funcibn para servidores de aplicaci6n JZEE y sus componentes a travCs de u n adaptador d e recursos JCA para crear y gestionar conexiones con u n recurso EIS, para ejecutar una operacibn con u n recurso EIS y para gestionar objetos/registros de datos corno entrada, salida o valores de retorno. La especificacih JCA recomienda que C C I debe formar la base para una funcionalidad mis rica y un modelo extensible de programacion proporcionado por 10s vendedores de adaptadores de recursos EIS, en lugar de ser el API utilizado por la mayoria de desarrolladores de aplicaci6n. Aunque C C I es independiente de un EIS especifico (por ejemplo, tipos de datos especificos de un EIS),

CCI puede ser controlado por metadatos especificos de EIS procedentes de un repositorio. El C C I
tambikn estd disefiado para utiliza la arquitectura JavaBeans y el sistema de sistema c o l l e c t i o n s de Java. Por ejemplo, un adaptador de recursos puede implementar la i n t e r f a z ~ a n a g e d ~ o n n e c t i o n ~ a c t o r y como un JavaBean, que mejoraria la capacidad de las herramientas del sistema JavaBeans para gestionar la ic otn F a c t o r y . configuraci6n de i n s t a n c i a s ~ a n a g e d ~ o n n e La especificaci6n J C A 1.0 recomienda (pero n o establece como obligatorio) que 10s adaptadores de recursos EIS implementen C C I como su API cliente, a la vez que t a m b i h requiere que estos adaptadores de recursos proporcionen 10s contratos de sistema con un servidor de aplicaci6n J2EE. Es conveniente sefialar que un adaptador de recursos tambien puede optar por tener un J2EE cliente adicional diferente de CCI, similar al API cliente provisto por el vendedor disponible en implementaciones JDBC. Los resultados de utilizar C C I son una mayor productividad para el desarrollador, un reducido coste de integraci611, c6digo portitil, sistemas de aplicaci6n reajustables y mantenimiento.

Interfaces y clases CCI


JCA define las interfaces y clases C C I que representan la siguientes partes:

La arquitectura de conectores J2EE


0

Interfaces de conexi6n- Representan la factoria de conexiones y una conexidn de nivel de aplicacion:

Interfaces de interacci6n- Proporcionan un componente para controlar una interaccion (especificado utilizando I n t e r a c t i o n r j p e c ) con una instancia EIS:

0 Interfaces de representaci6n de datos- Utilizadas representar estructuras de datos implicadas en

una interaccion con una instancia EIS:

Interfaces de metadatos- Proporcionar informaci6n bisica de metadatos sobre una implementacidn de adaptador de recursos y una conexion especifica de EIS:

Clases de excepci6n y advertencia- Proporcionan control de excepciones y advertencias de recursos durante la interacci6n con un recurso EIS:

A continuacion, presentamos una lista de interfaces/claes/m~todosJava del API C C I que es conveniente recordar:
0

j a v a x . r e s o u r c e . c c i .C o n n e c t i o n F a c t o r y - Unainterfazptibli~a~ueperrniteconexionesa una instancia EIS a traves de un adaptador de recursos. U n adaptador de recursos EIS proporciona normalmente esta interfaz. Una aplicaci6n busca una instancia C o n n e c t i o n F a c t o r y desde el espacio de nombres J N D I y la utiliza para obtener conexiones EIS, como muestra el siguiente fragment0 de codigo:
interface javax.resource.cci.ConnectionFactory extends java.io.Serializable, javax.resource.Referenceable throws ResourceException;
{

public

public RecordFactory getRecordFactory0

public Connection getconnection0 throws ResourceException; public connection getConnection(javax.resource.cci.ConnectionSpec properties) throws ResourceException; public ResourceAdapterMetaData getMetaData0 throws ResourceException;

o getconnection

( ) - Creaunainstancia Connection. Utilizar el m k t o d o g e t ~ o n n e c t i o n () con el parametro j a v a x . r e s o u r c e . c c i .C o n n e c t i o n s p e c requiere informacidn de seguridad y parametros de conexi6n.

especifica de lasolicitud 0 j avax . resource cci .connect i o ~ p e cProporcionalainformaci6n de conexi6n y propiedades como nombre de usuario, contraseiia y otros pardmetros a Connect ionFactor y mientras realiza una conexi6n a un EIS.

0 j avax resource. cci .Connect ion-Representa una conexi6n a un recurso EIS y se utiliza para posteriores operaciones con un EIS subyacente. 0 createInte raction ( ) - Crea un objeto Interaction pararealizar operaciones especificas de EIS. 0 j avax. resource. cci Interaction- Creaunainteraccibn con un EIS conectado con operaciones especificas, como muestra el siguiente extract0 de c6digo:
public interface javax.resource.cci.Interaction public Connection getconnection0 ; public void c l o s e 0 throws ResourceException;
(

public boolean execute (Interactionspec ispec , Record input, Record output) throws ResourceException; public Record execute(1nteractionSpec ispec, Record input) throws ResourceException;

0 Interact ionspec-Define la interacci6n que proporciona las propiedades de objeto especificas de EIS (por ejemplo, tipos de datos, esquema, etc.) asociadas a un EIS. 0 U n Record es la representaci6n Java de una estructura de datos utilizada como input o output de una funcidn EIS.

0 LocalTransaction- Crea un context0 de transaccidn para realizar, obviamente, una transacci6n local (similar a UserTransact ion) y gestiona su propia transacci6n y persistencia. javax. resource. cci .~ocal~ransactiondefineunainterfazdedemarcaci6npara transacciones locales de gestor de recursos, como se muestra a continuaci6n:
public interface javax.resource.cci.Lo~a1Transaction public void begin() public void commit ( 1 throws ResourceException; throws ResourceException; throws ResourceException;
(

public void rollback0

Para establecer una conexion a un recurso EIS y para efectuar interacciones como consultas y transacciones, el desarrollador necesita ajustarse a1 enfoque estdndar definido por la especificaci6n JCA 1.0. La especificaci6n explica dos situaciones para obtener una conexi6n a un EIS, que incluyen andlisis sobre la conexi6n a una aplicaci6n gestionada (aplicaci6n J2EE) y la conexi6n a una aplicaci6n no gestionada (applets o aplicaciones Java de dos gradas). En las siguientes secciones, analizaremos las dos situaciones y 10s pasos necesarios para conectar a interactuar con ellas.

La arquitectura de conectores J2EE


Conexion con una aplicacion gestionada (JZEE)
En este caso, la aplicaci6n obtiene una conexi6n proporcionada por la factoria de conexiones, configurada durante la implementaci6n de un m6dulo de adaptador de recursos en el senidor J2EE. Esta factoria de conexiones se define normalmente en el descriptor de implementaci6n del adaptador de recursos. El siguiente diagrama de secuencias UML muestra 10s pasos relacionados con la situaci6n en la que una aplicacion gestionada obtiene una conexi6n a una instancia EIS desde una factoria de conexiones y despues interactua con un EIS:

getConnection(Subject, ConnectionRequestlnfo)

rn

createlnteraction

Examinemos mLs detenidamente 10s pasos implicados.

1. El ensamblador de la aplicaci6n especifica 10s requisites de la factoria de conexi6n para un componente de aplicaci6n J2EE utilizando su descriptor de implementacidn (es decir, Web. xml o e j b - j a r .xml). Esta referencia de factoria de conexiones es parte del elemento < r e s o u r c e r e f > del descriptor para componentes EJB o Web (en lugar del adaptador de recursos). Asi, un ensamblador de recursos especifica 10s siguientes elementos en el descriptor de implementacidn para una referencia de factoria de conexiones:

2. El senidor de aplicaci6n J2EE utiliza el adaptador de recursos configurado para crear conexiones a1 recurso EIS subyacente.

3. El componente J2EE busca una instancia de factoria de conexiones en el entorno utilizando senicios JNDI. MLs concretamente:
//Obtener context0 inicial d e Nombrado

Capitulo 20
Context initctx
=

new

Initialcontext ( ) ;

/ / B f i s q u e d a JNDI p a r a o b t e n e r l a f a c t o r i a d e c o n e x i o n e s j avax. resource. c c i Cor~r~ectionFactory cf = ( j a v a z .r e s o u r c e . c c i . C o r ~ n e c t i o r ~ F a c t o r y ]

initctx.lookup("java:cornp/er~v/eis/wroxEIS") ;

Los resultados de la b h q u e d a J N D I en una instancia de factoria de conexiones de tip0 j a v a . r e s o u r c e . c c i .~onnection~actorycomoseespecificaene~ descriptorde implementacidn de la aplicaci6n. Tambikn debemos sefialar que, aunque no ha sido analizado, existe otro tip0 de factoria de conexidn para la Interfaz de Proveedor de Servicios (SPI).

4. La aplicaci6n invoca el mktodo g e t c o n n e c t i o n ( ) en la factoria de conexiones para obtener una conexidn EIS. Devuelve una instancia C o n n e c t i o n , que representa un controlador fisico para un EIS. Observe tambikn que el componente de aplicacidn puede obtener mdtiples conexiones invocando g e t c o n n e c t i o n ( ) en la factoria de conexidn como se requiere:
j avax. r e s o u r c e . c c i . C o n r ~ e c t i o n cx
=

Entonces la aplicacidn utiliza el m k t o d o c r e a t e I n t e r a c t i o n ( ) del o b j e t o c o n n e c t i o n p a r a crearunainstancia~nteraction. ja v a x . r e s o u r c e . c c i . I n t e r a c t i o n p e r m i t e a u n a componente ejecutar sus funciones EIS. El componente de la aplicaci6n crea instancias R e c o r d utilizando mktodo de crear R e c o r d F a c t o r y (~osmktodosdisponib~esinc~uyencreate~ndexed~ecord (), c r e a t e M a p p e d R e c o r d ( ) o c r e a t e ~ e s u l t ~ 0). et El componente de la aplicacidn u t i l i z a ~ o c a l ~ r a n s a c t i o definiendo n un context0 de transacci6n para realizar operaciones con un EIS. j a v a x . r e s o u r c e . c c i . LocalTransactiondefineunainterfazdedemarcaci6nde transacci6n para transacciones locales de gestor de recursos. El componente de aplicaci6n J2EE utiliza la interfaz L o c a l T r a n s a c t i o n para demarcar transacciones locales. Una vez que la aplicacibn J2EE termina con la c o n e x h , cierra la conexi6n utilizando el mktodo c x c l o s e ( ) en la interfaz c o n n e c t i o n . Si la aplicacidn n o cierra una conexidn asignada despuks de su uso, la conexi6n se considera no utilizada y el servidor de aplicaci6n se encarga de la limpieza de conexiones sin utilizar.

Conexion a una aplicacion no gestionada (de dos niveles)


En una situacidn de conexidn de aplicacibn n o gestionada, que implica a un applet a o a una aplicacidn Java de dos niveles, es responsabilidad del desarrollador de la aplicacibn crear un modelo de conectividad utilizando 10s API de nivel inferior expuestos por el equivalente del adaptador de recursos a1 de una aplicaci6n gestionada configurada en un entorno J2EE. Habitualmente, una aplicacidn n o gestionada conlleva la b h q u e d a de una instancia de factoria de conexibn, obteniendo una conexidn EIS, utilizando la conexidn para operaciones EIS y cerrando la conexi6n. Este modelo es similar a1 mod0 en que un cliente de a p k a c i 6 n JDBC de dos niveles accede a un sistema de base de datos en un entorno n o gestionado. El siguiente diagrama de secuencias muestra 10s pasos implicados en el proceso en que una aplicacidn no gestionada obtiene una conexidn a una instancia EIS desde una factoria de conexiones y despuks interactha con un EIS:

La arquitectura de conectores J2 EE

Gestionad

Recursos EIS

0
Recurso EIS

eManaged Connection

I I I I

Por lo tanto, la secuencia es de este modo:

I. El componente de aplicacidn no gestionada invoca un metodo sobre la instancia j avax. resource. cci .ConnectionFactory (devueltodelabusquedaJNDI) paraobtener una conexi6n a1 recurso EIS subyacente.
2. La i n s t a n c i a ~ o n n e c t i o n ~ a c t o delega ry la solicitud de conexidn procedente de la aplicacidn no gestionada en la instancia ConnectionManager provista por el adaptador de recursos. SegGn la especificacidn JCA 1.0, el adaptador de recursos EIS proporciona la implementaci6n de ConnectionManager como equivalente a1 servidor J2EE.

3. Entonces la instancia ConnectionManager crea una nueva conexidn a1 recurso EIS invocando
e~m~todo~anaged~onnection~actor~.createManagedConnection().

4. Lainstancia~anaged~onnection~actory manejael mktodo createManagedConnection ( ) creando una nueva conexi6n a1 recurso EIS representado por unainstanciaManaged~onnection. La i n s t a n c i a ~ a n a g e d ~ o n n e c onFactory ti utiliza Connect i onReques t Info y su conjunto configurado de propiedades (como el nGmero de puerto, nombre de servidor, etc.) para crear una nueva i n s t a n c i a ~ a n a g e d ~ o n n e c t i o n . 5. La i n s t a n c i a c o n n e c t i o n ~ a n a g e r invocael mktodo Managedconnection getconnection ( ) para obtener un dispositivo de conexi6n de nivel de aplicaci6n. Este, en realidad, proporciona un dispositivo temporal para que el cliente de aplicacidn no gestionada acceda a la instancia s u b y a c e n t e ~ a n a g e d ~ o n n ei con. t

6. Entonces la instancia ConnectionManager devuelve el dispositivo de la conexi6n a la instancia Connect i onFact ory, que devuelve entonces la conexi6n a1 cliente de aplicaci6n no gestionada que inicia una solicitud de conexidn.

Capitulo 20
7. La aplicaci6n utiliza entonces el m k t o d o c r e a t e ~ n t e r a c t i o n ( ) del o b j e t o c o n n e c t i o n p a r a c r e a r u n a i n s t a n c i a ~ n t e r a c t i o nj.a v a x . r e s o u r c e . c c i . I n t e r a c t i o n p e r m i t e a u n componente ejecutar funciones de EIS.
8. El componente de aplicaci6n crea instancias R e c o r d utilizando 10s mktodos de creaci6n ,create~appedRecord () R e c o r d ~ a c t o (rq ~u e i n c l u y e n c r e a t e ~ n d e x e d ~ e c o(r)d c r e a t e R e s u l t S e t 0).
9. El componente de aplicaci6n utiliza L o c a l T r a n s a c t i o n definiendo un context0 de transaction para realizar operaciones con un EIS.

10. Finalmente, una vez que la aplicaci6n no gestionada termina con la conexion, debe cerrar la conexidn utilizando el mktodo c x . c l o s e ( ) sobre la interfaz c o n n e c t i o n .

En el momento de publicacidn de este libro, 10s adaptadores de recursos con apoyo C C I apenas estaban disponibles, ni siquiera como implementacidn beta. Como tal, hemos estado utilizando 10s adaptadores de recursos de caja negra C C I provistos en la implementacidn de referencia J2EE en nuestros ejemplos. Observe que 10s adaptadores de recursos estaban en realidad destinados a probar el proceso de empaquetado y de implementacidn, asi como C C I .
En la siguiente seccibn, ilustraremos un ejemplo de uso de adaptadores de recursos de caja negra C C I y explicaremos c6mo escribir clientes de aplicaci6n J2EE para invocar mktodos de API C C I disponibles desde el adaptador de recursos. Tambikn analizaremos c6mo utilizar las diferentes clases e interfaces definidas por la C C I para acceder a un adaptador de recursos para una base de datos o un EIS.

Utilizar una CCI con adaptador de caja negra


El e, iem~lo es una a~licacion de libreria ficticia Dara aaadir libros nuevos v obtener la cantidad total disponible desde una base de datos. En este ejemplo, implementaremos un bean de sesi6n con estado, que utiliza un adaptador de caja negra de C C I para ejecutar procedimientos almacenados de SQL para consultar y ejecutar transacciones con un RDBMS. Es bastante similar a una aplicaci6n JDBC pero, en lugar de utilizar llamadas JDBC, el API C C I se utiliza para pasar parimetros y ejecutar 10s procedimientos almacenados de SQL en la base de datos subyacente. Los pasos necesarios en la implementaci6n del ejemplo B o o k s t o r e utilizando un adaptador de caja negra de C C I son 10s siguientes:
0

Implementaci6n de bean de sesi6n utilizando C C I Implementaci6n del adaptador de caja negra de C C I

0 Implementaci6n del bean de sesi6n 0 Prueba del adaptador de caja negra de C C I

Implementation de un bean de sesion con CCI


En este ejemplo Bookstore, se utiliza un bean de sesi6n con estado para mantener un registro del nlimero de libros en la tienda de libros. Nuestro bean invocari llamadas C C I sobre un adaptador de caja negra de C C I para ejecutar procedimientos almacenados en una base de datos. Como es habitual, nuestro EJB de sesidn contiene una interfaz initial ( B o o k s t oreHome), una interfaz remota (BookSt o r e ) , una clase de implementaci6n de bean (Book S t o r e B e an). Veamos ahora cdmo esta implementaci6n de bean de sesi6n utiliza llamadas CCI, analizando las interfaces y clase del b e a n ~ o o k s t o r e .

La arquitectura de conectores J2EE


La interfaz inicial
BookStoreHome simplemente define un metodo create ( ) para devolver una referencia a la interfaz

remota Book:
import j avax. ej b. * ; import j ava. rmi. RemoteException; public interface BookStoreHome extends EJBHome [ Booksstore c r e a t e 0 throws RemoteException, CreateException;
1

La interfaz remota
Bookstore contiene la definicidn para dos metodos de empresa: import j avax. ejb.EJBObj ect; import java.rmi.RemoteException; public interface Bookstore extends EJBObject { public void insertBooks(String name, int quantity) throws RemoteException; public int getBooksCount0 throws RemoteException;

I
La clase de implementation del bean
BookStoreBean es la clase de implementacidn del bean, que utiliza C C I . ~ o o k ~ t o r e ~ importa ean las interfaces CCI (es decir, j avax resource. cci *) y tambiknlas clases de la interfaz (com.sun.connect or. cciblackbox *) especificas del adaptador de cajanegra, junto con

javax.resource.ResourceException:
import import import import import import import java.math.*; java.util.*; j avax. ejb. * ; javax.resource.cci.*; javax.resource.ResourceException; j avax. naming. *; com.sun.connector.cciblackbox.*;

public class BookStoreBean implements SessionBean {

En el mktodo setsessioncontext ( ) , el bean utiliza variables de entorno para el nombre de usuario y la contrasefia para instanciar una ConnectionFactory para el adaptador de caja negra de CCI:
private private private private public public public public SessionContext sc String user; String password; ConnectionFactory void void void void ejbRemove ( ) { I ejbActivate ( ) ejbpassivate ( ) ejbcreate ( ) throws CreateException

{ )

public void setsessioncontext (Sessioncontext sc) { try { this.sc = sc; / / Establecer un context0 inicial JNDI Context ic = new Initialcontext ( ) ; / / Utilizar el mktodo 1ntialContext.lookup para tomar

Capitulo 20
/ / 10s valores de usuario y de contraseRa. user = (String) ic.lookup("java:comp/env/user"); password = (String) ic.lookup("java:comp/er~v/password~~ j; / / IJtilizar el mktodo de bkqueda para localizar ConnectionFactory y / / obtener una referencia a 6ste. ava: comp/env/eis/wroxCCIEIS" ) ; cf = (ConnectionFactory) ic. lookup ("j 1 catch (NamingException ex) { ex.printStackTrace ( ) ;

I
1

El bean utiliza su mktodo privado g e t c c I c o n n e c t i o n ( ) para establecer una conexibn con la base de datos utilizando el adaptador de caja negra. Con anterioridad a g e t c c I c o n n e c t i o n ( ) ,instancia un nuevo objeto c c i c o n n e c t i o n S p e c , que representa la implementacidn de l a i n t e r f a z ~ o n n e c t i o n ~ p e con c , 10s valores de usuario y de contraseiia obtenidos del context0 del bean, e invoca el mktodo g e t c o n n e c t i o n ( ) para obtener la conexibn. Se crea un controlador de conexibn al recurso EIS subyacente:
private Connection Connection con = try i / / Instanciar / / valores de getCCIConnection null;
( )

un nuevo objeto CciConnectionSpec con 10s usuario y de contraserla


=

ConnectionSpec spec

new CciConnectior~Spec (user, password) ;

// // // //
j

Utilizar CCIConnectionSpec para proporcionar 10s parimetros especificos de la conexi6n requerida a ConnectionFactory y y utilizar el mktodo getconnection de ConnectionFactory para obtener la conexibn a la base de daros.

con = cf.getConnection(spec); catch (ResourceException ex) ( ex.printStackTrace0;

I
return con;

I
El bean tambikn contiene un mktodo privado c l o s e c c I c o n n e c t i o n ( ) para cerrar una conexidn con el gestor de recursos. El bean de sesidn utiliza este mktodo internamente para invocar el mktodo c l o s e ( ) del o b j e t o c o n n e c t i o n . C o m o ya hemos aprendido anteriormente, si la aplicacibn n o cierra una conexidn asignada despuks de su uso, se considera que la conexibn n o esti utilizada y el servidor de la aplicacibn se encarga de la limpieza de conexiones sin utilizar (esto se aplica solamente a conexiones de aplicacidn gestionada). Esto finaliza una conexidn con el recurso EIS subyacente:
private void closeCCIConnection[Connection con) { try i con. close ( ) ; ] catch (ResourceException ex) { ex.printStackTrace0;

I I
Ahora que hemos definido 10s mktodos que permiten a nuestro bean interactuar con el recurso subyacente utilizando C C I , creemos 10s mktodos para efectuar operaciones con el recurso, en este caso, una base de datos.

La arquitectura de conectores J2EE


El bean de sesi6n B o o k s t o r e implements un mktodo i n s e r t B o o k s 0, que ejecuta una transacci6n local para insertar nuevos registros en la tabla ~ o o de k la base de datos. Este mktodo invoca el procedimiento INSERTBOOKS almacenado en la base de datos que ahade un nuevo registro con dos valores como argumento. Siendo lo habitual en una llamada de mktodo JDBC, el mktodo i n s e r t B o o k s ( ) establece primer0 una conexi6n a la base de datos (a travks del adaptador de caja negra) utilizando g e t c c I c o n n e c t i o n ( ) , despuks crea una nueva instancia I n t e r a c t i o n . Entonces el bean instancia un nuevo objeto C c i I n t e r a c t i o n S p e c para definir las propiedades de interacci6n de la base de datos requeridas para comunicar con una base de datos (como la configuraci6n del nombre almacenado de procedimiento y sus parimetros):
public void insertBooks(String name, int q t y ) [ try I / / Establecer una conexidn Connection con = getCCIConnection();
//

Crear una Interaction Interaction ix = con.createInteractioni)

/ / Instanciar un obj eto CciInteractionSpec CciInteractionSpec iSpec = new CciInteractionSpec(); // //

Confiqurar las propiedades de Interaction (Observe que 'null' configura el catilogo por defecto). iSpec. setFunctionName ("INSERTBOOKS"); iSpec.setSchema(user); iSpec.setCatalog(nul1);

/ / Utiliza ConnectionFactory para obtener RecordFactory RecordFactory rf = cf .getRecordFactory ( ) ;

/ / Invocar el metodo createIndexedRecord ("Ir~putRecord" ) ; IndexedRecord iRec = rf. createIr~dexedRecord / / Configurar 10s valores boolean flag = iRec.add(name) ; flag = iRec.add (new Integer iqty) ) ; / / Ejecuta la interacci6n ix.execute(iSpec, iRec);
1

finally { / / Cierra la conexidn closeCCIConnection(con); System.out.println("C10sed

connection");

1 1

El mktodo g e t B o o k s C o u n t 0, utilizando CCI, lee registros desde una tabla de base de datos subyacente ejecutando el procedimiento a ~ m a c e n a d o ~ 0 ~El ~ mktodo ~ ~ 0 0 utiliza ~ ~ .un I n d e x e d R e c o r d (elGnico registro apoyado en la actualidad por el adaptador de caja negra de CCI), que alberga sus elementos en una colecci6n indexada basadaen j a v a .u t i 1 .L i s t :
public int getBooksCount ( int count = -1; try I
)

/ / Obtener una conexi6n Connection con = getCCIConnection0; / / Crear una nueva instancia Interaction Interaction i x = con.createInteraction0;

Capitulo 20

/ / Instanciar un objeto CciInteractionSpec CciInteractionSpec iSpec = new CciInteractionSpec(); / / Configurar 10s par6metros para Interaction iSpec.setSchema(user); iSpec.setCatalog(nul1); ) ; iSpec. set FunctionName (ispec.setFunctionNameo;'COUNTBOOKS"

/ / Utilizar ConnectionFactory para obtener RecordFactory RecordFactory rf = cf .getRecordFactory ( ) ; / / Utilizar el metodo createIndexedRecord IndexedRecord iRec = r f . c r e a t e I n d e x e d R e c o r d ( " I n p u t R e c o r d " ) ; / / Ejecutar la interacci6n Record oRec = ix. execute (iSpec, iRec) ; / / Utilizar Iterator para recuperar elementos Iterator iterator = ( ( I n d e x e d R e c o r d ) o R e c ) . i t e r a t o r ( ) ; while(iterator.hasNext0) [ / / Extraer el elementos como un objeto Java Object obj = iterator.next ( ) ; if (obj instanceof Integer) { count = ( (1nteger)obj) . intvalue ( ) ; ) else if(obj instanceof BigDecimal) { count = ( ( B i g D e c i m a l ) o b j ) . i n t V a l u e ( ) ;

I I
finally { / / Cerrar la conexi6n closeCCIConnection(con); System.out.println("C1osed

Connection");

I
return count;
1

El detcriptor do implementadon EllB


Observe que, estavez, en el descriptor de implementacih, el elemento <resource-ref > (destacado en negrita) e ~ d e t i ~ o j a v aresource. x. c c i .ConnectionFactory:

< ! DOCTYPE

ej b-j ar PUBLIC \-//Sun Microsystems, Inc. //DTD Enterprise JavaBeans 2.0//ENf \http://java.sun.com/dtd/ejb-jar 2 O.dtdf>

La arquitectura de conectores J2EE

El cliente El cliente invoca 10s mktodos getBooksCount probar el adaptador de caja negra de CCI:
import import import import
()

y insertBooks ( ) sobre el bean de sesi6n para

java.uti1. * ; j avax. naming. Context; javax.naming.InitialContext; j avax. rmi. PortableRemoteObj ect;


{

public class BookStoreClient

public static void main(String[] args) { try I Context initial = rlew InitialContext ( ) ; Object obj ref = initial. lookup ("Bookstore")

BookStoreHome home = (BookStoreHome)PortableRemoteObject.r~arrow(objref, BookStoreHome.class); Bookstore book = home.create ( ) ; int count = book.getBooksCount ( ) ; System. err.println("Current Book count

"

count) ;

System.err.println("Insertir~g 2 new books.. . " ); book. insertBooks ("USA Tour guide", 100); book. insertBooks ("Europe Tour guide", 20);
count = book. getBooksCount ( ) ; System. err.printli-I ("Current Book count = " + count); catch (Exception ex) { System. err .println ("Caught an unexpected exception! " ) ; ex.printStackTrace0;

I
I
1

Implementation del adaptador de recursos de caja negra de CCI


Como sucede con el ejemplo anterior ~ e m o ~ c c o u n kste t , es un proceso de dos fases. Primero, necesitamos configurar la base de datos para crear la tabla y afiadir 10s procedimientos almacenados y, en segundo lugar, necesitamos implementar el adaptador.

Capitulo 20
Configurar la base de datos ~ s t es e un proceso ligeramente rnis complejo que el del ejemplo anterior porque, ademis de crear la tabla ~ o o k stambien , sera necesario que creemos 10s dos procedimientos almacenados. Utilizaremos de nuevo Cloudscape; sin embargo, esta base de datos tiene un metodo de manejo de procedimientos almacenados bastante inusual. Explicaremos el metodo inmediatamente, per0 antes creemos la tabla ~ o o k s . Utilice el siguiente SQL para crear la sencilla tabla ~ o o k s :
CREATE TABLE Books (name VARCHAR(32), qty INTEGER);

Volvamos ahora a 10s procedimientos almacenados. Para utilizarlos con Cloudscape, necesitamos escribir una clase Java que proporcione la implementaci6n del procedimiento utilizando JDBC bisico. Entonces, en la base de datos, creamos un ALIAS para 10s procedimientos almacenados que apuntan a esta clase. Asi, para nuestro procedimiento almacenado COUNTBOOKS, afiadiremos un metodo a nuestra clase que sea como el siguiente:
import j ava. lang. Integer; import j ava. sql. * ; import java. lo.*; public class BookProcs implements Serializable { public static int c o u n t B o u k s 0 [ int count = 0; try { Connection con = DriverManager. getConnectior~ ("jdbc: cloudscape: ;current=truel') ; Preparedstatement ptstmt = con.prepareStatement ("SELECT COUNT ( * ) FROM BOOKS") ; Resultset rs = ptstmt.executeQuery(); while (rs.next ( ) ) { count = rs.getInt ( 1) ;

I
ptstmt.close();

1 catch (Exception ex)


ex.printStackTrace

{ ( ) ;

I
return count;

Entonces afiadimos el s i g u i e n t e a ~la ~base ~ ~de ~ datos Cloudscape:


CREATE METHOD ALIAS COUNTBOOKS FOR BookProcs.countBooks;

Recuerde que puede ejecutar SQL bien utilizando directamente Cloudview o desde una linea de comando utilizando la invitation c l o u d s c a p e - i s q l desde % 5 2 EE-HOME% \ b i n .
Observe que, para que esto funcione, necesitamos asegurarnos que la clase B o o k P r o c s se encuentra en la ruta de clase de la base de datos. El modo ma's fa'cil de realizar esto es modificando la variable B J P E E - C L A S S P A T H I (configurada en elarchivo u s e r c o n fig. b a t ) .

Para el procedimiento almacenado INSERTBOOKS, afiada otro metodo a B o o k s P r o c s :


public static void insertBooks (String name, int q t y ) [ try Connection con = DriverManager .getConnectior~ ("jdbc:cloudscape: ;currer~t=true") ;

La arquitectura de conectores J2EE


Preparee2Statemer1t ptctrnt c i i n . ~ t r e ? a r e S t a t e m e r ~{t" I N S E R T p t s t m t . s e t S t r i n g (1, n a m e ) ; p t s t r n t . s e t 1 n t ( 2 , qty); ptztrnt executeUpdateI) ; ptstmt.clcse0; c a t c h ( E x c e p ti a n e x ) ! cx.prir,tStackTrace ( ) ;

INTO BOOKS

VF.LI.IES

I ?, ? ) " ) ;

i
1

C'PEATf

blETHOI?

ALIAS

1NSERTBOOk:S

FOR

Fn\?kProc.=.insertRnr,ks;

Irnplementacion del adaptador


Utilizaremos un mktodo similar al utilizado anteriormente, excepto que, csta vez, implementaremos el archivocciblackbcx-tx. rar. C o n cl servidor d e la Implementaci6n d e Referencia 12EE 1.3 ejecutindose, abra la hcrramienta d e implelncntaci6n y Cree unn nueva aplicacidn I l a n l a d a C C I A d a p t e r :

1Ch20~.CCIAdaptenCc3'IAdapter.ear

Browse...

Afiada entonces un archivo r a r del adaptador dc rccursos existente c o m o hiciCramos anteriormente pcro,estave~,se~eccioneelarchivo'J2EE-HOME\ 1 ~ b \ c o n n e c t o r \ c c ~ b l a c k b o x - t e xr. a r antes de implernentnr la npl1caci6n de empresa. Arnplie el nodo del servidor hasta que pueda ver su servidor cn ejecucidn (con toda probabilidad, l o c a l h o s t ) y selcccione el servidor de In ventnna de la parte izquierda. En la ventana de la dcrecha, cnmbie a la opcion Resource-adapters y haga clic en el boton New. En el cuadro de d i d o g o New Connection Factory (Nueva factoria de conexion), s e l e c c ~ o n e c c ~ ~ d a p:tcecrl b l a c k b o x - t x . r a r corno Resource-adaptery otorguele un Nornbre JNDI, e i s / W r o x C C I E I S , c o m o se muestra a continuaci6n:

Capitulo 20

Conwcllur~ Factory JNOI Nnrrln:

rrj.;.hriiaxi:cIEgi,
Cor~fiijlrralinn Propeflies-

PropertV ConneclronURL

I
String

Twe

value jdbc cloudscape rml Clou

-1

Aseglirese d e que la propiedad ConnectionURL apunta a In base de datos correcta (en nuestro caso, CloudscapeDB) y haga clic en OK para afiadir el adaptador:

FTiiGiFo;
p

~ blackbox-tx rar
cp elwWroxE1S
eisl~row~~l~w

@ CClAdapler 9 tclblatkbox-bcrar

EM."

La arquitectura de conectores J2EE


Ahora que ya hemos irnplernentado el rn6dulo del adaptador de recursos de caja negra de C C I con una factoria de conexiones en el servidor de la Irnplernentaci6n de Referencia J2EE 1.3 y hernos creado las tablas de la base d e datos y 10s procedirnientos alrnacenados, estarnos preparados para irnplernentar el bean de sesi6n y ejecutar el cliente.

Implernentacion y prueba de l a aplicacion CCI


Compile 10s archivos java EJB, recordando afiadir el archivo c c i b l a c k b o x - t x . r a r (que se encuentra en el fichero c c i b l a c k b o x - t x . rar) a su ruta de clase y afiidalos entonces a la herrarnienta de irnplementaci6n utilizando el asistente de creaci6n de EJB o generando su propio archivo J A R EJB:

C j Applical~ons
0-

9 0 CClAdapter 0- @ BookStore
G% CciBlackBoxLocalTn

0 Blackbox

P Sewers

Ref Type !esource -

Referenced By ( Reference Name BookStore ewWroxCCIEIS -1

JNDl Name

s i s W i r o ~ 7 :lE_ISU

Afiada 10s nornbres J N D I relevantes e irnplernente de nuevo la aplicaci6n, recordando crear esta vez el archivo J A R del cliente. Finalmente, ejecute el cliente utilizando una linea de cornando corno rnostrarnos a continuaci6n. Si t o d o funciona corno es debido, o b t e n d r i el siguiente resultado:

Capitulo 20

Asi concluye nuestro e j e ~ n p l o B o o k s t o r e que utiliza el adaptador d e recursos de caja negra de C C I para interactuar con una base d e datos Cloudscape.

Ventajas de la arquitectura de conectores JZEE


C o n el esito de JZEE en aplicacibn d e elnpresa de base Web, se preve claramente que J C A se alzarl como el principal mccanismo d e integracidn para interactuar con recursob EIS de segundo plano. En conveniente recordar un par de importante ventajas:
-1 1

J C A permite a las orgnnizaciones aumentar las ventajas d e sus sistemas EIS existentes y d e JZEE. J C A permite a 10s desarrolladores escribir (o reescribir) nuevas aplicaciones utilizando JZEE, cncapsulando partes funcionales de aplicaciones existentes en EJB o en componentes Web.

Annlicemos brevemente algunas situnciones en las que J C A ofrece una soluci6n potential, centrindonos en las ventajas obvins.

Integration de aplicacion de empresa (EN) con JCA


Gestionar e integrar diversas aplicaciones EIS para compartir datos y procesos habitualmente aiiade retos al desarrollo, transacciones, seguridad y reajustabilidad de una aplicaci6n. C o m o 10s recursos EIS se construyen esclusivamente con su propio API d e propiedad y sus propios mecanibmos de transacci6n y s e p r i d a d , se hace e x t r e m ~ d a m e n t e complejo construir un sistema EAI utilizando mliltiples API de propiedad y adaptando mecanismos nativos. Aunque m a estrategia EAI requiere un catllogo de requisitos, con una combinaci6n de diferentes tecnologias de adaptador, en la mayoria de 10s casos se termina con unas limitaciones y cuestiones relacionadas con la reajustabilidad del sistema debido a un API d e propiedad o a mecanismos no estindar. En ocasiones, puede terminar m l s bien como un k t i d o de aplicaciones de empresa que corno una integracibn. J C A proporciona una arquitectura estindar que arregla esas deficiencias de soluciones EAI comunes. C o n una larga lista de vendedores de EIS respaldando J C A mientras proporcionan adaptadores de recursos especificos de EIS, J C A presenta caracteristicas de integracibn sin fisuras con su API de C C I independiente de la aplicacibn, apoyando las transacciones distribuidas y mecanismos de seguridad genkricos y especificos d e la aplicacibn.

Portales de empresa capacitados con JCA


Los portales de empresa normalmente cubren la necesidad de ofrecer un linico "escritorio" corporativo que unifica toda la informacibn, servicios, aplicaciones y procesos para 10s miembros de una empresa, como empleados, socios y clientes. Integrar contenido y aplicaciones utilizando una infraestructura

La arauitectura de conectores J2EE


genirica afiade complejidad si ello conlleva la integracion con aplicaciones heterogineas de segundo plano y sistemas de legado con arquitecturas de propiedad y mecanismos de seguridad. Los portales generalmente requieren un acceso global que requiere apoyo centralizado de autentificacion y autorizaci6n para aplicaciones heterogineas y transacciones distribuidas con multiples sistemas de informacidn de empresa. Por lo general, 10s portales son aplicaciones con una misi6n esencial que demandan gestionabilidad central y de alta disponibilidad. Fornlando parte de la familia J2EE, JCA es ideal para construir portales de empresa. C o n el exit0 de 10s portales basados en J2EE, J C A mejora 10s recursos EIS distintos de Java permitiindoles formar parte de un portal de empresa de base J2EE. Las mejoras relevantes inchyen:
O

API C C I independiente de la aplicacion Mecanismo de acceso EIS que apoyan mecanismos de autentificacion especificos de la aplicaci6n Transacciones distribuidas basadas en componentes J2EE con apoyo XA

D e este modo, JCA representa claramente una solucion perfecta para elevar aplicaciones EIS a un portal de empresa.

Integracion empresa-a-empresa con JCA


La integracih empresa-a-empresa (B2B) mejora la automatizaci6n del proceso de extremo a extremo y permite la interaccion de la aplicaci6n en el interior de una empresa y entre socios a travis de Internet. Para apoyar verdaderamente la's interacciones externas de socios comerciales, 10s sistemas internos de segundo plano necesitan estar integrados sin fisuras en el mismo proceso. Sin ello, la integracion de procesos de extremo a extremo n o puede lograrse. Aunque XML sobre H T T P proporciona integracion de cliente B2B dentro de una empresa y en Internet, tiene sus propias limitaciones en cuanto a integracion aplicacion-a-aplicaci6n, seguridad y transacciones. JCA resuelve el puzzle B2B proporcionando e ~ ~ e c i f i c a m e nintegracion te con recursos EIS de segundo plano y demuestra una integracion genuina de proceso de extremo a extremo. J C A puede ser implementado para consultar y trasladar datos con recursos EIS de segundo plano, y 10s datos pueden ser convertidos posteriormente en XML utilizando 10s API XML de Java para la interacci6n B2B con socios. C o n la capacidad de C C I y sus desarrolladores de API independientes de la aplicaci6n, podemos manejar cualquier mecanismo de seguridad de nivel de aplicaci6n y cualquier transacci6n distribuida con multiples recursos EIS. Contar con aplicaciones de servidor de empresa basadas en la plataforma J2EE para utilizar J C A permite tener aplicaciones B2B de gran reajustabilidad son comprometer el valor y la funcionalidad de recursos EIS. Queda claro que J C A ofrece innumerables ventajas a 10s usuarios reduciendo el coste de construir complejas soluciones EAI, mejorando la productividad del desarrollador, la protecci6n de la inversion de arquitecturas estindar y la ampliaci6n de aplicaciones personalizadas.

Elementos que faltan en JCA 1.0


En las secciones anteriores, hemos analizado las funciones y 10s factores m i s prometedores de la Arquitectura de Conectores J2EE 1.0; concluyamos ahora analizando 10s elementos que faltan en esta version de la especificaci6n.

Capitulo 20
Los dos elementos clave que faltan en la especificaci6n 1.0 de la Arquitectura de Conectores J2EE son:
0

La actual especificaci6n no es compatible con la comunicaci6n asincrona y s61o es compatible el modelo de comunicacidn sincrono solicitud/respuesta. Esto puede resultar un problems restrictivo para conectar con colas de mensajes. aunque C C I puede utilizarse para compatibilizar XML.

0 N o existe un mecanismo integrado de compatibilidad XML disponible para recuperar datos XML,

Estas limitaciones se resolverin en la siguiente versidn de la especificacion (JCA 1.1). para mas detalles, consultehttp://java.sun.com/j2ee/connector/.

En este capitulo, hemos realizado un recorrido por la Arquitectura de Conectores J2EE 1.0, demostrando con ejemplos el uso de adaptadores de recursos de caja negra provistos con la ImplementaciCln de Referencia T2EE 1.3. Hemos analizado c6mo se enfrenta la arauitectura de conectores T2EE a sus soluciones para resolver cuestiones de integration de aplicacidn surgidas en la industria actual. Este capitulo tambikn ha explicado y demostrado 10s pasos implicados en la integraci6n e interacci6n con un EIS utilizando el API de Interfaz Comun de Cliente (CCI). Hemos analizado:
0

El rol de la Arquitectura de Conectores J2EE

U La Arquitectura de Conectores J2EE y sus elementos


0 0
0 0 0

Los adaptadores de recursos Implementaci6n y prueba de un adaptador de recursos Programaci6n con la Interfaz Comun de Cliente (CCI) ImplementaciCln y prueba de una aplicaci6n debase J C A Ventajes potenciales de J C A

0 Estado actual de la especificaci6n y elementos ausentes

En el siguiente capitulo, examinaremos algunas de las consideraciones de diseiio mis importantes que se deben tener en cuenta a la hora de desarrollar nuestras aplicaciones J2EE. C o n la ayuda de algunos diagramas UML, veremos una serie de patrones especificos de J2EE que pueden aplicarse para resolver algunas cuestiones comunes de diseiio.

Consideraciones de diseiio para aplicaciones JPEE


La Plataforma Java 2, Enterprise Edition (J2EE) ofrece una gama completa de tecnologias 6tiles. Hasta ahora, hemos dedicado gran parte de este libro a tratar esas tecnologias y a estudiar cdmo deben ser aplicadas. La clave para crear aplicaciones aprovechables, flexibles y mantenibles estP e n aplicar tecnologias apropiadas a1 contexto del problema a resolver. En este capitulo, examinaremos algunas de las formas mls comunes de aplicar tecnologias J2EE para resolver cuestiones de disefio en determinados contextos. Analizaremos 10s siguientes temas:

CI Q u i queremos decir cuando hablamos de disefio y arquitectura


O

La relacidn entre disefio y el contexto en que tiene lugar Las fuerzas que intervienen en el disefio de una tipica aplicacidn de e-comercio para la plataforma J2EE Una variedad de patrones especificos de J2EE que resuelven cuestiones comunes de disefio que surgen a1 disefiar sistemas de empresa basados en J2EE

Las ventajas y desventajas de varias tecnologias J2EE a1 ser aplicadas en ciertos contextos de diseho

Capitulo 21

El mundo sigue cambiando


Cuando 10s vendedores de software (normalrnente enfrentados) estin de acuerdo en algo, ies un buen o un ma1 presagio? Considere las plataformas de aplicaciones de empresa prornovidas p o r - ~ u n y por Microsoft. Desde un nivel superior, la Plataforrna Java 2 Enterprise Edition (J2EE) y .NET Framework (anteriorrnente personificado en Windows Distributed Internet Architecture, o D N A ) asustan un poco. de obietos distribuidos. Arnbas cornbinan rndtiples niveles, clientes infradotados o dotados, ~rotocolos API de acceso estandar, servicios de rnensajeria, entornos de cornponentes de grada media y transacciones.

..

La llegada del cornercio electr6nico y las escalas de tiernpo de Internet ha carnbiado el modo de definicibn y desarrollo de la rnayoria de las aplicaciones de ernpresa. Los requisitos son mds exigentes que antes y las escalas de tiernpo son rnenores. Hay una necesidad creciente de soluciones rnis adaptables ya que, segurarnente, 10s requisitos de ernpresa de rnafiana no serin 10s rnismos que 10s de hoy. Para disefiar y desarrollar aplicaciones en estas condiciones, necesitarnos ayuda seria (algunos dirian "profesional"). Esta ayuda norrnalrnente adopta dos forrnas:
E I Un

sistema estandarizado en el que las aplicaciones pueden ser construidas y desplegadas. El sisterna debe proveer niveles apropiados de funcionalidad y debe tarnbitn ayudar a autornatizar la creaci6n de "conexiones" estindar para conectar la aplicaci6n a si rnisrno.
U n conjunto de las mejores pricticas para utilizar ese sistema. Los desarrolladores de software no tienen una cantidad de tiernpo infinita para invertir en la conternplaci6n de la filosofia del disefio o en aprender 10s rnodos rnis eficientes de utilizar ciertos API. Lo que necesitamos son directrices que les ayuden a escribir buenas aplicaciones utilizando el sisterna.

C I

En tirminos Java, el sistema para el desarrollo de aplicaciones de empresa distribuidas es JZEE. Las caracteristicas y funcionalidad de la plataforma permiten la creaci6n de aplicaciones reajustables, distribuidas, flexibles y basadas en componentes.
Los cliches anteriores son s61o unos cuantos de los que se aplican regularmente a J2EE en la "propaganda" media del rnercado. Son rnuy flciles de prorneter per0 rnucho rnis dificiles de ofrecer. A la hora de crear aplicaciones o cornponentes de aplicaci6n, 10s requisitos corno nivel de reajustabilidad deben ser especificados y disefiados. La arquitectura subyacente de la aplicaci6n es un elernento clave a la hora de deterrninar si esos requisitos son asequibles. J2EE proporciona 10s cirnientos sobre 10s que puede construirse la arquitectura de las aplicaciones rnodernas Java, de ernpresa y de cornercio electronico. Ahora, con la versi6n 1.3, la plataforrna J2EE ofrece rnis sofisticaciones en el uso de Enterprise JavaBeans (EJB), apoyo XML nativo, seguridad perfeccionada y un sisterna gentrico de conectores de recursos. Aunque esto acarrea algunas herrarnientas y estrategias rnis, no cambia el rnodo fundamental en que se aplica J2EE. Las estrategias de disefio siguen siendo pricticarnente iguales. De hecho, la naturaleza del disefio es que la mejor aplicaci6n de herrarnientas y tecnologia s61o se descubre desputs de que tstas hayan sido utilizadas durante un tiernpo. El andlisis de 10s patrones presentados en este capitulo en una buena reflexi6n sobre esta cuesti6n. El carnbio desde la version 1.2 a la versi6n 1.3 de J2EE ha consistido, en realidad, en afiadir rnis funcionalidad per0 ?es una ventaja o una lacra? Recienternente, incluso 10s vendedores han llegado a cornprender que 10s desarrolladores necesitar ayuda para explotar el octano de funcionalidad que ya se encuentra a su alcance. Sun Microsystems ha creado las Directrices de Disefio Blueprints Sun para J2EE (referidas aqui como "J2EE Blueprints") y Java Pet Store para ilustrar las rnejores prdcticas para la plataforrna J2EE. Puede encontrar J2EE Blueprints en http://java.sun.com/j2ee/blueprints/.

Consideraciones de diseho para aplicaciones J2EE


N o existe un mod0 facil de obtener 10s conocimientos requeridos para un disefio efectivo de aplicacih en una plataforma de empresa. La version 1.0 de J2EE Blueprints tiene alrededor de 350 piginas. Ademis, existe tambikn una multitud de diversos recursos, como libros, e-mail/grupos de noticias, informes y articulos que proporcionan nuevas perspectivas, anilisis, consejos y, en ocasiones, opiniones controvertidas sobre la creaci6n de aplicaciones de empresa. A continuaci6n, una muestra de estos recursos:

O Software Architecture in Practice, Bass, Clements y Kazman. ISBN 0-201-19930-0


O
O

Client/Sewer Programming with Java and C O R B A , Orfali y Harkey. ISBN 0-471-24578-X Enterprise JavaBeans, Second Edition, Mozon-Haefel. ISBN 1-565-92869-5

The Java 2 Enterprise Edition Developer's Guide (referenciado en la documentacion J2EE y disponible enhttp://java.sun.com/j2ee/docs.html)
Lista de e-mail para debates sobre Patrones J2EE en Sun, registrese en http:// developer.java.sun.com/developer/technicalArticles/J2EE/patterns/WhatsNext.html

O Debates sobre disefio en http://theserverside.com/discussion/index.jsp

Los pensamientos y las opiniones que se encuentran en estas fuentes (y muchas mas) no pueden condensarse en un capitulo. Por lo tanto, el resto del capitulo examina algunos de 10s principales puntos del desarrollo de empresa y 10s tipos de solucion que se aplican en un entorno J2EE.

Arquitectura y diseno
El uso de 10s tkrminos "arquitecto" y "arquitectura" en el mundo del desarrollo de software es el tema central de algunos debates. En tkrminos de construccion, el papel de un arquitecto es razonablemente bien comprendido. En tkrminos de software, se utiliza regularmente y es intercambiable con el tkrmino "diseiio". La arquitectura de una aplicacion puede definir algunos o todos 10s puntos siguientes:
O
0

Los componentes que realizan las tareas de empresa de la aplicaci6n El tip0 de interaccidn entre dichos componentes

o Los servicios utilizados por esos componentes


La plataforma subyacente que ofrece o apoya esos servicios
O Otras caracteristicas o capacidades (como reajustabilidad) que se enfrentan a la no funcionalidad

En conjunto, la arquitectura de una aplicaci6n proporciona un sistema en el que se pueden tomar decisiones individuales, de disefio detallado. La idea de que una aplicaci6n se ajusta a un determinado tip0 de diseiio puede contribuir a aclarar su estructura completa. A1 considerar estos temas, utilizaremos el tCrmino arquitectura en su significado general de la estructura o forma de una aplicaci6n.
-

Estilos de arquitectura
Se hace referencia a arquitecturas basadas en servicios y arquitecturas constituidas por capas o gradas. Sin embargo, n o consiste en hacer una eleccion directa entre 10s tkrminos. Muchos sistemas utilizan aspectos de multiples estilos de arquitectura para resolver diferentes partes de su problema general.

Capitulo 2 1
Las arquitecturas estratificadas y gradificadas tienen mucho e n comun. E n muchos sentidos, las arquitecturas gradificadas pueden percibirse c o m o una forma concreta de arquitectura estratificada. El principal objetivo es abstraer algunos elementos de u n sistema para simplificar la estructura general. Una capa o estrato representa u n cluster de funcionalidad o componentes que tienen caracteristicas similares, p o r ejemplo, tipo de funcion o localizaci6n fisica. Cada capa proporciona funcionalidad a las capas que le rodean. A1 analizar arquitecturas estratificadas, muchos pensarin en capas descendentes, como las que vemos en una pila de sistemas. En el modelo O I S de una pila de sistemas, por ejemplo, la capa de transporte hace uso de la funcionalidad provista por la capa de red, que, a su vez, utiliza la funcionalidad de la capa de vinculo de datos. Esta estratificacion proporciona a b s t r a c c i h de las capas subyacentes para permitir la sustituci6n. En tirminos de nuestra aplicacion, la plataforma JZEE proporciona multiples niveles: hardware, sistema operativo, J2EE y la misma aplicacibn, como se muestra en este diagrama:

----

Nlvel

de

Hardware

Puesto que la aplicaci6n se asienta sobre la plataforma JZEE, el hardware o sistema operativo subyacente puede ser modificado para proporcionar mejores caracteristicas (por ejemplo, mas rapidez, menos costes, rnis estabilidad) sin necesidad de rescribir partes de la aplicaci6n. Las arquitecturas de nivel son un tipo especifico de arquitectura estratificada basadas e n una vista del sistema centrada en el usuario. E s t o provoca una division desde la parte frontal hacia atris con el usuario situado en la parte frontal y 10s datos subyacentes (y demis) en la parte posterior. U n a tipica arquitectura de tres niveles consiste en:
0

U n nivel de interfaz de usuario que representa 10s datos de aplicacion para el usuario y, a travis de la cual, el usuario interactua con la aplicacion. U n nivel de empresa que encapsula la 16gica de ernpresa de la aplicaci6r1, por ejemplo, 10s pasos implicados en la presentacion de una reclamaci6n de seguros. U n nivel de datos que proporciona acceso a fuentes de datos subyacentes, como bases de datos, aplicaciones Enterprise Resource Planning (ERP) o sistemas principales. Este nivel tambiin se denomina a veces nivel de Servicios de Informacion de Empresa (EIS).

Los niveles reflejan cierta forma de division fisica, de tal mod0 que 10s tres grupos de componentes existirin en diferentes procesos y, habitualmente, en diferentes miquinas. La comunicacion fluiri entre 10s diferentes niveles a medida qua la aplicaci6n realiza sus funciones. El uso de niveles hace que la separaci6n de problemas sea rnis ficil de juzgar. U n a d e las motivaciones clave para arquitecturas estratificadas en que reducen el acoplamiento entre componentes de diferentes capas. Los componentes altamente acoplados tienen conocimientos detallados de 10s otros componentes con 10s que interactuan. Esto significa que son rnis dificiles de sustituir o de reubicar individualmente. Definiendo las funciones en conjunto desempehadas por 10s componentes en cada nivel, resulta rnis ficil crear interfaces fijas entre niveles y reducir asi el acoplamiento entre 10s componentes de esas capas. La separacion de la interfaz de usuario, la logica de empresa y el acceso a datos nos permite sustituir mejores productos o ticnicas en cada nivel sin perturbar a1 resto. Esto desemboca en una aplicaci6n rnis flexible.

Consideraciones de diseiio para aplicaciones J2EE


U n a aplicaci6n t a r n b i h puede utilizar una arquitectura gradificada por rnotivos de reajustabilidad. El desacoplarniento entre niveles nos perrnite afiadir rnis capacidad a cada nivel a rnedida que el sisterna se reajusta. U n ejernplo consistiria en afiadir rnis servidores Web en el nivel de interfaz de usuario para servir a rnis clientes. Esto n o requeriria autorniticarnente rnis servidores de bases de datos en el nivel de datos (aunque podria). Podernos ver a continuaci6n una arquitectura de tres niveles de base Web:

Grada EIS

Serv~dorde Datos
I'

Chente Web Nwel de Presentac~bn N~vel

U n a arquitectura basada en servicios percibe 10s cornponentes de u n sisterna en tkrrninos de servicios de caja negra. U n ejernplo desde el punto de vista del nivel de sistema seria un servicio de transacci6n, corno el A P I de Transaccion Java (JTA) provisto p o r J2EE. E n este caso, el usuario del servicio s610 se encarga de la interfaz y de las caracteristicas del sisterna, n o de su irnplernentacion. Las arquitecturas basadas en servicios pueden ser percibidas corno una forrna mayor de arquitectura de cornponentes puesto que las aplicaciones serin creadas por prograrnas de creaci6n o directivas que invocan diferentes servicios para ejecutar sus tareas requeridas. El concepto de u n servicio cornienza a alejarse del concepto de clientes y servidores fijos puesto que 10s servicios pueden solicitar a otros servicios que realicen sus tareas. N o existe ningun requisito irnplicito para que las llarnadas fluyan en una direction concreta. Los servicios pueden ser verticales u horizontales: 10s servicios verticales reflejan requisitos funcionales, corno servicios de aprobaci6n para pedidos de cornpra, rnientras que 10s servicios horizontales proporcionan rnecanisrnos subyacentes, como autentificacion o persistencia.

Contexto de diseno
El software se desarrolla para resolver u n problerna. Ese problerna puede ser de naturaleza ernpresarial, tip0 c6rno reducir la cantidad de tiernpo que supone para una organizaci6n procesar el pedido de u n cornprador, o puede ser rnis tkcnico, corno garantizar que un sisterna de control por satilite responde correctamente cuando se le instruye para rnodificar la trayectoria. E n arnbos casos, n o se puede ernitir u n

Capitulo 2 1
juicio absoluto de la calidad de la soluci6n propuesta. So10 se puede juzgar la soluci6n en el contexto del problema que debe ser resuelto. Considere el diseiio de un avi6n. La sabiduria convencional sugeriria que la estabilidad es un factor muy importante para el disefio de un avi6n. Sin embargo, muchos modernos aviones de guerr? son diseiiados intencionadamente para ser inestables puesto que esto mejora su capacidad de maniobra. Esta es una buena decision de disefio para un caza puesto que una ligera mejora en la capacidad de maniobra puede suponer la diferencia entre el kxito o el fracas0 de una misi6n. Asimismo, las organizaciones que utilizan aviones estin dispuestas a pagar 10s caros sistemas de procesamiento informitico que contribuyen a convertir una miquina inestable en una miquina que puede ser controlada por un piloto humano. Si modifica el contexto del problema, por ejemplo analizando en un pasajero del avian, las consideraciones de seguridad son primordiales. De repente, la estabilidad se convierte en un punto muy importante, mucho mas que la capacidad de maniobra. Para un avi6n de este tipo, la capacidad extra de maniobra no merece arriesgar la seguridad o el coste de sistemas operativos extra para controlar un avi6n inherentemente inestable. Por ello, la correcta decision de diseiio en un contexto puede, en un contexto ligeramente diferente, ser la decision err6nea. Ninguna decision de diseiio es inherentemente buena o mala, todo depende del contexto y de 10s factores internos y externos que influyan en el disefio (a menudo denominados fuerzas). Esto se aplica a1 modelado de la soluci6n propuesta y a la asociacion del modelo a la plataforma subyacente. Entonces, <aquk nivel cubre este capitulo cuestiones de diseiio? Esencialmente, es un reflejo de algunas consideraciones, concesiones, pdcticas ideales y regias bisicas que se encuentran normalmente a1 asociar cierta forma de modelo superior a la plataforma J2EE. Este es, entonces, el disefio que se encuentra entre el analisis y la implementaci6n. Parte de este disefio puede ser independiente de la tecnologia de implementaci6n. A1 perfeccionarse un modelo UML, algunas de estos perfeccionamientos funcionan bien en todas las arquitecturas potenciales. Otros perfeccionamientos deben verse influidos por la plataforma en que son desplegados. A1 analizar aspectos especificos de diseiio, resulta util tener un contexto en el que juzgar las decisiones. Teniendo esto en cuenta, proporcionaremos el contexto en este capitulo mediante el uso del estudio de un sencillo caso de comercio electronico. Mis concretamente, se presentari el diseiio y desarrollo de una tipica aplicacion de compra, y sus requisitos asociados. Ademis, examinaremos correctas pricticas de diseno J2EE explorando las cuestiones de diseiio que rodean a un sistema para presentar y procesar pedidos de compra. Esto proporciona un contexto para juzgar las ventajas e inconvenientes de determinadas decisiones de disefio.

Los requisitos de empresa


Nuestra compafiia ficticia, Acme Multinational Plc., desea automatizar sus sistemas de compra que manejan la creation, presentation y procesamiento de pedidos de compra.

El sistema existente
En la actualidad, un empleado'debe buscar 10s productos que requiere en catilogos impresos de mliltiples proveedores. Estos catilogos son de variada edad y exactitud. El empleado debe rellenar un pedido de compra en papel que enumerando 10s articulos que desea. Debe proveer informaci6n adicional, como su localizaci6n y el codigo del departamento. El formulario completo es entonces enviado via correo interno a1 gestor apropiado para su aprobacion. El gestor juzgari primer0 si 10s articulos son relevantes para la funci6n del empleado y despuks consultari sus hojas de cilculos financieras, o telefoneari a1 departamento de contabilidad, para comprobar si el presupuesto del departamento es suficiente para financiar la compra. Puede que tambikn exista un limite personal que debe ser comprobado en el caso de ese empleado. Si 10s articulos son inapropiados, o no hay

Consideraciones de diseiio para aplicaciones J2EE


suficientes fondos, el gestor rechazari la orden de cornpra y la enviari de vuelta a1 particular. Esto puede durar hasta un period0 de dos semanas despuis de la p r e s e n t a c h inicial del pedido. Si se aprueba la solicitud de compra, se reenvia a1 departamento de compras que separari 10s articulos que proceden de diferentes proveedores. En esta fase, puede que descubran que 10s articulos especificados proceden de catilogos antiguos y ya no se abastecen o que el precio ha cambiado. Quizis hay carnbiado el proveedor de un determinado tipo de articulo, lo que significa que la especificaci6n ha cambiado. En todos estos casos, el solicitante original debe ser inforrnado de 10s cambios y la orden de compra puede requerir potencialmente que vuelva a sorneterse de nuevo al proceso cornpleto.

El sistema deseado
La intenci6n que es que todo el sistema existente sea automatizado. El objeto general es ahorrar costes reduciendo el nGmero de interacciones humanas requeridas para procesar la orden de compra y, consecuenternente, reducir la posibilidad de error. El sistema tambikn debe mejorar la moral de 10s empleados acelerando el procesamiento de 10s pedidos y elirninando la necesidad de un segundo procesamiento. Los requisitos funcionales generales incluyen 10s siguientes:

O Toda la informacidn del catilogo seri provista on-line. Esto garantiza que toda la informaci6n esti actualizada y reduce el nGrnero de modificaciones necesarias en 10s pedidos. Tarnbiin proporciona la capacidad de lirnitar 10s articulos ofrecidos a 10s empleados basindose en su funci6n y e n el presupuesto individual de compra. O El empleado rellenari la orden de cornpra on-line. Los articulos s61o pueden ser aiiadidos seleccionindolos en el catilogo on-line (es decir, no son introducidos por el ernpleado). Esto debe proporcionarse en una aplicaci6n estilo carro de la compra que resulte familiar a 10s usuarios Web. La informaci6n estindar sobre ese empleado concreto, como su ubicaci6n y el c6digo de departamento, se insertari automiticamente en el documento basindose en la identidad autentificada. Asi se reducirin errores debido a la introducci6n incorrecta de cddigos de product0 y c6digos de departamento. O El ernpleado presentari la orden de compra on-line. El presupuesto individual de un ernpleado puede ser cornprobado en el mornento del envio del pedido y el pedido puede ser rechazado inmediatamente si supera el presupuesto. El gestor a1 que se envian 10s pedidos estari deterrninado por la identidad a partir de la identidad del ernpleado, o a partir de 10s contenidos del pedido (es decir, un pedido de un ordenador puede dirigirse a1 gestor de T I en lugar de a1 gestor de lineas del empleado). El documento seri entregado electr6nicarnente el gestor.

El gestor puede ver cualquier orden de compra que se le envie on-line. El misrno sisterna debe otorgarle acceso a cifras de presupuesto del departamento actualizadas al minuto y tambikn a cualquier regla de compra que se aplique a su departamento. Cualquier orden de compra recibida durante la ausencia del gestor debe ser encolada para un posterior examen.

O El gestor puede aprobar o rechazar on-line la compra. Cualquier pedido rechazado seri enviado de vuelta a1 empleado electr6nicamente. La aprobaci6n tendri como resultado que el pedido sea reenviado a1 sistema de compras, una vez se haya comprobado automiticarnente que esa compra no excederi el presupuesto del departamento.

O El sistema de compra se encargari de fraccionar la orden de cornpra y agrupari en lotes 10s


articulos procedentes de diferentes pedidos de cornpra requeridos del rnismo proveedor. Esto puede servir para obtener descuentos por lotes de algunos proveedores presentando todos 10s pedidos a la vez. Todos 10s pedidos se presentarin a 10s proveedores electr6nicamente; idealrnente, a travis de la Web per0 puede tambiin realizarse a travis de un fax. La informacidn de la orden de compra seri registrada de forrna que esti disponible para 10s empleados que reciban las mercancias y que enviarin 10s articulos recibidos a 10s empleados solicitantes. Todo esto ahorra gran cantidad de tiempo de procesamiento, curnplimentaci6n y recuperaci6n de pedidos de compra.

Capitulo 2 1
Ademis del verdadero procesamiento de 10s pedidos de compra, la ernpresa sitfia otros requisitos en el sistema.

El context0 de empresa
Existen tarnbien requisitos clave del sistema que no estin directamente relacionados con el procesamiento de pedidos de compra:

O Reajustable- el sistema debe reajustarse para poder servir a la plantilla de75000 empleados de Acme.
Hasta 8000 de estos usuarios pueden estar conectados a la vez, aunque no todos ellos estarin necesariamente utilizando el sistema de pedidos.
0

Distribuido- el sistema debe ser accesible desde todos 10s sitios de Acme. Puesto que Acme ya tiene una Intranet que abarca toda la compafiia, se prefiere en gran medida un sistema de base Web. Flexible- debe ser posible afiadir ficilmente nueva funcionalidad a medida que sea requerida por 10s cambios de la prictica de empresa.

0 Basado e n componentes- el sistema debe adaptarse a un sistema de componentes de modo que sea posible adquirir componentes comunes directamente de la tienda para formar parte del sistema en lugar de construir todo desde la nada. Esto ahorra tiempo y costes de desarrollo.

Ademis, uno de 10s requisitos no funcionales mis comunes para sistemas es un "reducido tiempo de compra". Los sistemas son requeridos con urgencia per0 con mayor funcionalidad, reajustabilidad, etc. que antes. Seria imposible construir todo lo requerido en el margen de tiempo proporcionado a partir de API sencillos, de nivel inferior. Lo que se requiere es un entorno que proporcione un sistema comun para albergar componentes comprados o construidos alrededor de 10s cuales pueda construirse la aplicacion. El entorno debe proporcionar tambien una gran cantidad de funcionalidad "fuera de la caja" y presenta al desarrollador abstracciones de nivel superior que facilitan su uso. En el pasado, la aplicaci6n era la autoridad suprema hasta el punto que so10 confiaba en la funcionalidad bisica de su sistema operativo o entorno subyacente. Esto podia deducirse de 10s esfuerzos para portar aplicaciones entre diferentes plataformas. Entornos como JZEE contribuyen a elevar el nivel en este sentido. Mucha de la funcionalidad que formaba parte anteriormente de la aplicaci6n puede ser delegada en otra parte (en capas horizontales o servicios verticales). Esto da lugar a la "aplicaci6n disgregable" puesto que el c6digo de la aplicacion mismo forma s61o una pequefia parte de la funcionalidad total. Puesto que hay una inversi6n menor en la aplicacion, &a puede ser rescrita mis a menudo y desechada mis ficilrnente cuando se queda obsoleta. Las aplicaciones de comercio electr6nico son tipicas de este tip0 de aplicaci6n (o deberian serlo). Esta transici6n se muestra en el siguiente diagrama:

Plataforma deLegado

Los cortos periodos de desarrollo esperados para aplicaciones de comercio electr6nico han cambiado el modo que se desarrollan 10s sistemas. En un informe sobre comercio electr6nic0, Gartner afirma que la transici6n es un "programa, no un proyecto". Esto refleja las realidades en un mundo de requisitos de empresa que cambian ripidamente. En un entorno de este tipo, una aplicaci6n comercial no puede seguir siendo igual durante dos o

Consideraciones de disefio para aplicaciones J2EE


tres aiios despuis de la creacion. Los carnbios requeridos para la aplicaci6n en ese rnargen de tiernpo serin significativos (no sirnplernente arreglos de errores y rnejoras de capacidad de uso). Para evitar convertirse en una aplicaci6n de legado, debe evolucionar constanternente para cubrir las dernandas carnbiantes.

Elaborar 10s requisitos


Una vez han sido definidos 10s requisitos funcionales, puede construirse un rnodelo que encapsule el proceso de ernpresa y sus principales entidades de ernpresa. Puede utilizarse UML para capturar 10s principales elernentos del sisterna tal y corno estin descritos en 10s requisitos funcionales. Esto creari un rnodelo del "dorninio del problerna", es decir, el verdadero sisterna de ernpresa que debe ser implementado.

Construir el modelo
U n rnodelo de primer paso para el sisterna de nuestro ejernplo es el siguiente:

I Y
t l o l i l 0 double

Esste n o es, en absolute, el articulo terrninado per0 proporciona una base alrededor de la cual puede analizarse las decisiones de diseho. De hecho, algunas de las decisiones de diseho afectarin a la evolucih del

1105

modelo. Las fases iniciales de anilisis y diserio conllevan la creaci6n de un modelo que asocia el problema que debe ser resuelto. Las entradas para la creaci6n de este modelo son 10s casos de uso o las historias de uso que describen la funcionalidad del sistema deseado. De hecho, nuestra lista de requisitos de empresa serialada en la secci6n El sistema deseado podria formas 10s inicios de un conjunto de casos de uso. Estas entradas pueden cristalizarse en anotaciones U M L como diagramas de clase y diagramas de secuencia. Este modelo inicial de dominio de problema, que refleja cosas "reales" (personas, documentos, etc.), se utiliza entonces como la base sobre la que crear un modelo de la soluci6n propuesta (las clases, componentes e interacciones que conformarln el sistema de software). Esta soluci6n puede ser moldeada hasta cierto punto por el entorno en el que sera desplegada. Aunque esto n o se define necesariamente en este punto, 10s comentarios si indican que J2EE es el entorno de destino, como veremos mis adelante. El modelo del sistema es razonablemente simplista y no hay duda de que hay muchos aspectos del modelo que podemos elaborar, o donde podemos organizar las cosas de un modo algo diferente. Recuerde, sin embargo, que todas las soluciones reflejan el contexto de su diserio y una de las principales fuerzas en este caso es que el modelo debe ser lo suficientemente sencilla para ser comprendida enseguida. La intenci6n en esta fase temprana es capturar la esencia del sistema y no necesariamente el detalle. Esto es suficiente para analizar el cambio de modelo a arquitectura de sistema. N o es necesario que construyamos un modelo completo de trabajo y asi quedarnos estancados en el detalle de sistemas de compra. Puede ver una soluci6n mis comprometida (0, de hecho, evolucionada) para un sistema de comercio electronico de n niveles en Java Pet Store, provista como parte de JZEE Blueprints.

Exploracion el modelo
U n ripido vistazo el modelo del sistema revela que la construcci6n de un pedido de compra se centra en la clase P r o d u c t . Los productos pueden ser enumerados a partir de cierta base (c6digo de producto, categoria) y presentados a1 usuario. Los productos seleccionados por el usuario serin almacenados en un S h o p p i n g c a r t representado por una serie de L i n e I t e m s . La interacci6n con el usuario estari controlada por O r d e r i n g W o r k F l o w , que encapsula la ldgica de interfaz de usuario para mostrar productos, seleccionar productos y presentar una orden de compra. C o m o parte del proceso de pedido, la orden de compra debe ser enviada a1 gestor adecuado. Esto requeriri cierta forma de identificaci6n del usuario asi como del gestor. Para este prop6sit0, pueden reunirse las credenciales del usuario. Cuando se haya presentado la orden de compra, se comprobari teniendo en cuenta limites del departamento de diverso tipo, incluido la cantidad de dinero disponible en el presupuesto del departamento. El pedido de compra producido sera almacenado en a l g h lugar, quedando pendiente de recuperaci6n por el gestor. El gestor avanzari a travts de la bgica de interfaz de usuario A p p r o v a l ~ o r k ~ l o para w comprobar y aprobar o rechazar 10s pedidos presentados. Esto, en esencia, es la aplicaci6n que debe ser implementada. Sin embargo, hay muchas mis decisiones que deben tomarse para hacer que este modelo evolucione hacia una implementaci6n utilizando tecnologias J2EE.

Elaborar el contexto
Una vez se ha construido el modelo de dominio del problema, debe surgir un modelo de dominio de soluci6n a partir de 61. Este modelo estari sujeto a fuerzas del "mundo real" del desarrollo de la aplicacion como las capacidades de las herramientas y 10s entornos aplicados, la topologia de la infraestructura en la que va a ser desplegada la aplicaci6n y las habilidades disponibles para el desarrollo.

Consideraciones de diseho para aplicaciones J2EE

Adaptarse al terreno
Considere un arquitecto "real" disefiando una casa. A1 arquitecto se le solicitan una serie de requerimientos que establecen que la casa debe tener cuatro dormitorios, un bafio, un cuarto de estar, garaje, etc. Si la casa debe ser construida en la ladera de una colina, el disefio seri diferente del de una casa disefiada para una parcela llana de tierra. El disefio de la primera puede hacer uso de la pendiente del suelo para situar el garaje por debajo del resto de la casa, o puede construir partes de la casa en el interior de la ladera de la colina para mejorar sun eficiencia termodinimica. De un mod0 similar, en software la sohci6n que evoluciona desde un modelo bisico sera diferente dependiendo del "terreno" en que seri desplegada la aplicaci6n. U n patr6n que sea predominante en este entorno puede sugerir una soluci6n conveniente para un problema concreto (corno el garaje de la planta baja del ejemplo anterior). De este modo, el entorno dari forma a1 modelo del mismo mod0 que 10s requisitos iniciales. El modelo evolucionado puede proporcionarnos informaci6n Gtil sobre el sistema como las relaciones entre las diferentes clases. Esta informaci6n resulta muy util a la hora de decidir sobre cuestiones de implementaci6n como estructuraci6n de componentes y empaquetado. De nuevo, si existe una restricci6n conocida relacionada con el despliegue de diferentes partes del sistema (por ejemplo, un componente debe residir en un determinado sewidor de base de datos), entonces esto puede sipificar que dos componentes relacionados no pueden ser empaquetados juntos. Esto, a su vez, afecta a las relaciones entre las clases implicadas y, por lo tanto, afecta a la forma del modelo. En este caso, la interfaz de una o mis de las clases implicadas puede necesitar ser modificada para permitir 10s efectos de distribuci6n, o puede introducirse una clase proxy. En nuestro caso, el terreno es J2EE. Esta elecci6n puede tomarse por varios motivos:
0

La organizaci6n puede contar con muchas habilidades en el desarrollo de Java establecida para el desarrollo de la aplicaci6n

0 Los sewidores de aplicacion de base Java o J2EE pueden formar parte de una plataforma estindar 0

U n sewidor de aplicacion de base J2EE puede ofrecer un rendimiento o funcionalidad superior en comparaci6n con otras alternativas

Cualquiera que sea el motivo, 10s disefiadores de la aplicacion podrin sacar partido del sistema basado en componentes provisto por el sewidor de aplicaci6n J2EE.

La distribuci6n se encuentra en el centro de las aplicaciones J2EE y, como tal, es parte principal del paisaje J2EE. La distribuci6n de la funcionalidad proporciona mucha de la flexibilidad de la plataforma J2EE. Sin embargo, el anilisis y el disefio de alto nivel no consideran la distribuci611, intentando primer0 crear 10s adecuados componentes de empresa. En este mundo ideal, todos 10s accesos entre clientes y servidores serian transparentes, como si 10s servicios estuvieran localizados en la misma miquina. La distribuci6n tambikn introduce complejidad en forma de llamadas de mCtodo adicionales y diferentes paradigmas de programaci6n. Todo esto deberia haber quedado claro con la lectura de 10s primeros capitulos de este libro, concretamente de la lectura de 10s capitulos dedicados a J N D I y a RMI. En un entorno distribuido, las llamadas de mCtodo ya no son determinantes como lo son en el procesamiento local. Por ejemplo:

o Una llamada puede fallar debido a un error relacionado con la red


0

U n fa110 parcial de una operaci6n redificada puede provocar problemas. Esto debe ser detectado y corregido por la aplicaci6n

Capitulo 21
O Surgen cuestiones de coordinaci6n y secuencia. N o hay garantia del orden en que seri recibida una

secuencia de llamadas procedentes de mliltiples procesos Tambikn pueden considerarse otros factores:
O El tiempo invertido en una llamada de mktodo en la red seri muchos 6rdenes de magnitud superior

que el invertido en una llamada de mktodo local.


O

El potencial para comunicaci6n para dominar el procesamiento. Concurrencia implicita en el sistema. La necesidad de localizar repetidamente componentes remotos mientras migran entre sewidores en el tiempo. datos en el sistema en cualquier momento.

0
O

o Los niveles de imprevisibilidad, que hacen dificil o imposible garantizar la consistencia de todos 10s
Estas y otras cuestiones deben ser consideradas a la hora de disefiar soluciones para entornos distribuidos. Puede encontrar un buen anilisis, quizis algo anticuado, sobre 10s temas relacionados con la distribuci6n en el documento A Note on Distributed Computing, de S. C. Kendall, et al. 1994, disponible e n http://www.sun.com/research~echrep/l994/abstract-29.html. El diserio de interfaces entre componentes distribuidos es un arte en si mismo. Las interfaces de componentes distribuidos deben conformarse a las buenas pricticas habituales para cualquier interfaz. Los mktodos de una interfaz deben formar un conjunto cohesivo en vez de una colecci6n dispar. Los mismos mktodos deben ser operaciones con significado, no simplemente un conjunto de accedentes de propiedad. C o m o sucede con todo buen disefio, el minimalismo es un buen principio siempre que n o Cree demasiado trabajo extra para el usuario de la interfaz (se permite una cierta cantidad de desregularizaci6n). U n ejemplo podria ser una situation en la que un linico mktodo toma muchos parimetros. Si puede identificar un conjunto de tareas comunes para la que existen varios mktodos por defecto, puede crear un mktodo para cada una de estas tareas. Desde un punto de vista purista, estos mktodos extra pueden parecer un derroche pero, desde un punto de vista prictico, pueden ahorrar mucho c6digo cliente innecesario para crear o especificar parametros vacios o estindar. A la hora de crear sistemas distribuidos, como aplicaciones J2EE, debe diseiiar las interfaces entre 10s componentes para tener en cuenta la distribuci6n. Debe tener cuidado a la hora de decidir si pasar objetos por referencia o por valor. Pasar por referencia es flexible per0 puede desembocar en un sobregasto creciente a travks de llamadas remotas. Pasar por valor contribuye a la interaction local en el cliente per0 no siempre es la solucion ya que puede provocar problemas a clientes distintos de Java. Si s61o se requiere una pequefia parte de 10s datos, pasar un objeto por valor puede provocar mayor sobregasto que un mont6n de llamadas distribuidas. Ademas, pasar por valor n o resulta apropiado para datos que cambian rapidamente. En el context0 de nuestro sistema de 6rdenes de compra, debemos asegurarnos que seguimos 10s siguientes pasos: Dividir bien el sistema, de mod0 que 10s componentes que se comunican frecuentemente y sueltos sean colocados en el misma equipo siempre que sea posible. Puesto que la comunicaci6n en una red es comparativamente lenta y compleja, debemos intentar eliminarla alli donde sea posible. En el sistema de orden de compra, n o tendria sentido que el S h o p p i n g c a r t estuviera en un equipo diferente a o r d e r i n g W o r k F l o w . Esto aumentaria innecesariamente la complejidad de la interaccidn entre estos componentes.
O Cuando la comunicaci6n por red es inevitable, es pricticamente seguro que

O r d e r i n g W o r k F l o w estari en un equipo distinto a P r o d u c t L i s t e r . Existen patrones comunes de disefio en el irea del procesamiento distribuido que pueden ayudar el diseiiador al

Consideraciones de disefio para aplicaciones J2EE


enfrentarse a este tipo de problems. En un nivel prictico, estos patrones pueden realizarse como el uso de metodos en lote entre componentes o de JavaBeans serializados para albergar instantineas de datos. Algunos patrones especificos de J2EE para distribution serin analizados mis adelante, en este capitulo. El diseiio de sistemas distribuidos es dificil. Es importante tener un buen conocimiento de lo aue esti sucediendo bajo las cubiertas del sistema y de quk tipos de transacciones se estin llevando a cabo. Este conocimiento le permitiri tomar decisiones de disefio informadas para mantener a1 sistema desacoplado v eficiente. Sin embargo, para obtener estos conocimientos, no es necesario que escriba cada linea de su codigo. El tipo de software intermediario tipificado por J2EE ayuda a1 disefiador y a1 desarrollador proporcionando mucha de la infraestructura y del "codigo pegamento" requerido a la hora de desarrollar sistemas distribuidos. Las ventajas de estos contratos y servicios, y el uso de la interposicih, ya han sido analizadas anteriormente en otro capitulo. La necesidad de ofrecer rendimiento, reajustabilidad e integridad de datos en sistemas distribuidos subyace en mucha de la funcionalidad provista en J2EE. Algunos ejemplos de estas caracteristicas son:

o Contenedores que no pueden controlar la concurrencia y optimizar el rendimiento a la vez que


mantienen el aislamiento

O Transacciones distribuidas para integridad de datos O Pase de mensajes para mejorar el rendimiento, la reajustabilidad y enfrentarse a varios niveles de di~~onibilidad
0

U n servicio de nombrado que proporciona independencia de localizaci6n

Elegir y perfeccionar una arquitectura


La necesidad de distribuir componentes es solo uno de 10s factores habituales que empiezan a transformar el modelo de dominio idealizado en un disefio concreto que puede ser implementado en un conjunto determinado de equipos que utilizan un determinado lenguaje y entorno de periodo de ejecuci6n. Esta evolucion conllevari primero la selecci6n de una arquitectura completa que se ajuste a 10s requisitos. Una vez se conozca la arquitectura global, puede tomarse una serie de decisiones de disefio que asociarin esa arquitectura con exit0 a 10s sistemas, plataformas y estructuras subyacentes.

Arquitectura para el sistema de pedidos de compra


Hasta el momento, hemos destacado la necesidad de juzgar arquitectura y disefio en su contexto. Los requisitos de diferentes tipos de aplicaci6n en su arquitectura de aplicaci6n variarin, por ejemplo:

O Aplicaciones de comercio electr6nico Muchos clientes, mucha lectura, menos actualizaci6n, bajo contenido para recursos clave, un amplio conjunto de datos en funcionamiento que fomentan el uso de a1 cache. O Bancos y cajeros Muchos clientes, bajos niveles de acceso concurrente, alto nivel de aislamiento, ningGn conjunto de datos en funcionamiento que deba ser alamacenado en cache.
Los requisitos influirin ampliamente en las decisiones relacionadas con su arquitectura. Los tipos de aplicacidn mis comunes dan lugar a plantillas de arquitectura. Los sistemas de pedidos de compra se ajustan a un tipo de aplicaci6n c o m h : aplicaciones de comercio electronic0 de base Web. Por lo tanto,

Capitulo 21
utilizari una arquitectura estindar para este tip0 de aplicaci6n, es decir, una arquitectura de tres niveles que utilice un cliente (navegador Web) infradotado. Existen otras plantillas de arquitectura para diferentes tipos de aplicaciones. Dentro de esta arquitectura, deben tomarse varias decisiones de diserio. El disefio puede considerarse como la solucion a un problema en un contexto dado. El contexto consistiri en una serie de fuerzas que deben ser comprendidas y sopesadas por el disefiador. Habri diversas fuerzas en funcionamiento limitando la arquitectura de empresa, corno:
0

El problema de empresa y su modelado

rn Tecnologias requeridas incluido 10s sistemas de legado rn Cualidades deseadas del sistema: reajustabilidad, disponibilidad, etc.
0

Alcance de la aplicacion (es decir, el numero de usuarios para 10s que esti disponible la aplicaci61-1). Esto se representa normalmente como clientes (de aplicacibn) dotados frente a infradotados (navegador Web) puesto que las aplicaciones de base Web son mas faciles de poner a disposition de un publico mas amplio, de ahi que tengan un mayor "alcance".

Todas estas fuerzas, y muchas mis, afectaran la forma especifica del sistema eventual y la arquitectura que mejor se adapte. La idoneidad de un disefio depende enteramente de su contexto, es decir, de 10s problemas encontrados y las fuerzas en funcionamiento en el sistema. Anteriormente, a la hora de definir 10s requisitos para el sistema, se han especificado varias fuerzas como la necesidad de procesar 10s pedidos de compra asincronicamente y el deseo de implementar el sistema sobre J2EE.

Iteration y retroalimentacion
Las fuerzas sobre la evolucion del sistema pueden ser funcionales o no funcionales y pueden variar desde nivel alto a nivel bajo. Tal y como esto implica, el disefio debe tener lugar en muchos niveles y fases:
O El modelo de solucibn (aunque puede ser llamado una "elaboraci6n" del modelo de problema).

0 Laampliaarquitectura de sistema.
O Interfaces de componentes de sistema.

o Interacciones entre componentes de sistema.


O Aspectos internos de componentes de sistemas individuales.

2Implica esto que la arquitectura es una salida de disefio? Afortunadamente, la respuesta es "sin.Sin embargo, la arquitectura t a m b i h puede evolucionar ademis de ser disefiada, per0 disefiar una arquitectura implica un proposito. Los efectos de decisiones de arquitectura de alto nivel atraviesan el disefio. Si la necesidad de reajustabilidad se traduce en el uso de un modelo sin estado, entonces esto mismo puede afectar las decisiones de bajo nivel, como el uso de EJB de sesi6n sin estado y el estilo de sus interfaces. Requisitos semifuncionales como la capacidad de ampliacion pueden tener un impact0 de gran alcance sobre decisiones de disefio en todo el sistema. Tomando el ejemplo de la capacidad de ampliacion, si un sistema utiliza en la actualidad dos posibles mecanismos de intercambio de datos per0 se prev6 se requeririn mis, podria crearse una capa extra para acomodar las ampliaciones requeridas. De un mod0 similar, se tomarin otras decisiones en niveles inferiores de la jerarquia de la aplicacion por razones de eficiencia o idoneidad para la plataforma subyacente. Estas decisiones pueden entonces retroalimentar la cadena y requerir cambios para partes de nivel superior de la arquitectura. Asi se

Consideraciones de disefio para aplicaciones J2EE


formarin 10s ciclos de retroalimentaci6n. La mayoria de procesos formales de desarrollo de linea general, como Rational Unified Process (http://www.rational.com/products/rup/) y extreme Programming (XP) (http://www.arrnaties.com/extrerne.htrn), abarcan una idea de iteraci6n y retroalimentaci6n entre las fases de un desarrollo de software. Las cuestiones de implementaci6n o las tecnologias cambiantes pueden generar retroalimentaci6n vilida en el diseho o en el anilisis de alto nivel. Recuerde que la mayoria de 10s problemas tienen multiples soluciones. Si la retroalimentaci6n cambia las fuerzas operativas en un determinado punto, una decisi6n diferente bien podria ser apropiada. Por ejemplo, puede suceder que la necesidad de que Line I t em haga referencia a un P r o d u c t para recuperar el precio de un articulo desemboca en incompetencias que ralentizan el sistema. Puede que se decida replicar esta informaci6n de precio en el mismo Line1 tern para reducir estas incompetencias. Esto modificari ligeramente el modelo del sistema de pedidos de compra mostrado previamente, pero la funcionalidad global permanece intacta. Entonces, tqut significado tiene esto para el diserio? Significa que debemos enfrentarnos al diserio como a un proceso continuo, n o como a un evento Gnico. Enfrentarse a ello de esta forma puede en realidad reducir el coste y 10s efectos de decisiones de diserio incorrectas. A lo largo de la vida de una aplicaci6n, el paisaje tecnol6gico cambiari. Este paisaje forma parte del context0 en el que se toman las decisiones de diserio. Por ello, lo que se necesita es una aceptaci6n de que el cambio tendri lugar y de que debe ser incluido como factor en el ciclo de vida de la aplicaci6n.

La aceptacion del cambio desemboca en proyectos en 10s que la funcionalidad distribuida en etapas, donde el diseiio evoluciona a medida que el proyecto progresa y donde la refactorizacidn es una parte de la vida. Los cambios en tecnologia y en cuestiones de implementaci6n deben retroalimentar la cadena de modo que sus implicaciones puedan ser tenidas en cuenta en la asociaci6n del modelo de problema con el modelo de solucion (Frank Buschmann utiliza un yoy6 como analogia para este efecto).
Aunque una arquitectura abierta y flexible es un buen factor, debe procurar no dedicar demasiado tiempo a convertir simples clases en bibliotecas o estructuras que nunca serin explotadas. Es Gtil tener en mente el principio de extreme Programming representado con las siglas YAGNI, procedentes de la frase en inglts "You Ain't Gonna Need It" (Novas a necesitarlo), al considerar tales ejercicios.

Aplicar patrones
Muchos desarrolladores de software en pricticas no tendrin tiempo de seguir el debate informado sobre la naturaleza del diseiio y la arquitectura. Incluso si lo siguen, su esperanza es extraer algo de uso concreto que les ayudari a realizar una elecci6n mejor o mis informada la proxima vez que se sienten a diseriar un sistema. Los patrones son una muy buena fuente de informaci6n sobre arquitectura y diserio para diseriadores de software que esttn practicando.

lQue son 10s patrones?


U n principio clave en muchas disciplinas profesionales es no reinventar la rueda. Los ingenieros civiles y 10s arquitectos saben mucho sobre diseiio de edificios. En la creaci6n de la mayoria de edificios, no se necesitan ideas nuevas, solo las aplicaciones de mecanismos comunes de disefio que han sido utilizados con anterioridad en muchas ocasiones. En su mayor parte, la ingenieria de software todavia n o ha alcanzado este nivel de madurez, por lo que todavia existe una tendencia a enfrentarse a cada proyecto con un lienzo en blanco. Se dice que Picasso dijo que "Los buenos artistas copian, 10s grandes artistas roban". Aunque tiene algunas connotaciones negativas, refleja la realidad del diserio en que Cste consiste

Capitulo 21
ampliarnente en una sintesis de muchas ideas de diversas procedencias aplicadas a1 contexto deseado. Ningun disefiador de software tendri un conjunto de ideas completamente nuevo sobre cdmo crear sistemas de software; la clave, como en otras disciplinas, es reunir conocimientos de mod0 que todos 10s disefiadores de software puedan crear mejores sistemas. O t r o comentario, esta vez de Bill Joy de Sun, reflejaba el hecho de que no todas las buenas ideas proceden de dentro de Sun, por lo que la gente debe estar abierta a ideas procedentes de otros origenes. Afortunadamente, 10s desarrolladores de software tienden a ser amigos de compartir pensamientos e ideas y, en el caso de la comunidad Open Source, tambitn c6digo. Esta tendencia a cooperar y reunir ideas ha llevado a1 desarrollo de catilogos de patrones de disefio de software que son de disposicion publica y que pueden contribuir en el disefio de una variedad de sistemas de software. U n patr6n es una soluci6n comprobada para u n problema en u n contexto dado. C u a n t o m6s amplio sea el contexto, m6s amplio s e d el campo de aplicaci6n del patr6n. En tirminos de software, 10s patrones son esencialmente la destilaci6n de la "sabiduria" obtenida por especialistas sobre lo que funciona bien a la hora de especificar, disehar e implementar software. El movimiento de patrones de software se populariz6 inicialmente gracias a 1 libro Design Patterns - Elements of Reusable Object-Oriented S o h a r e , de Gamma et al., Adison-Wesley, ISBN 0-201-63361-2. Sin embargo, 10s patrones no se aplican hnicamente en 10s dominios de la micro-arquitectura como se describe en este libro. Los patrones pueden encontrarse en muchas ireas de software y sistemas. En un nivel superior, 10s patrones pueden encontrarse a1 realizar anilisis en campos especificos. Las entidades y relaciones descubiertas durante estos anilisis se repetirin a en el sector de empresa. Esta repetici6n desemboca en el descubrimiento de dichos patrones. Si esti trabajando en un dominio especifico, como finanzas o telecomunicaciones, seria conveniente investigar la existencia de patrones especificos del dominio para ahorrar tiempo y esfuerzos. Los patrones tambitn pueden ser especificos de una determinada tecnologia o lenguaje (en ocasiones descritos como "locuciones" cuando son rnis especificos). Los patrones especificos de Java existen en una variedad de niveles hasta llegar a las locuciones del lenguaje.

Patrones JZEE
En este libro, son de miximo inter& 10s patrones que se aplican especificamente a JZEE. Probablemente, la representation mis visible de este interts es el trabajo realizado por algunos de 10s arquitectos Java del Sun Java Center. Han creado un conjunto de patrones especificos de Java basados en varios afios de implementaciones pricticas de sistemas de base J2EE llevadas a cab0 por la armada de Servicios Profesionales de Sun. El conjunto de patrones se encuentra on-line en Java Developer Connection y estin siendo desarrollados y perfeccionados gracias a debates a travts de la lista de correo sobre Patrones J2EE (j2eepatterns-interest@java.cun.corn). Los patrones JZEE de Sun Java Center tienen como claro objetivo sistemas de empresa de n niveles y estin clasificados tomando como base el nivel en el que residen, es decir, Presentation, Empresa e Integration. La siguiente tabla presenta algunos de 10s ejemplos de patrones mis comunes del catilogo.

1 Nivel
Presentacih

Patrdn Controlador frontal

Descripci6n Introduce un controlador central (servlet o JSP) que controla la gestion de servicios de sistema de nave aci6n como sonutilizados un tipico f h j o de trabajo k b a s e Web.

Consideraciones de diseho para aplicaciones J2EE


Nivel Patr6n
Vista de conlposici6n Fachada de sesion

Descripci6n
Proporciona flexibilidad en la presentacion de la informacion construyendo la vista global de la pagina Web a partir de u n conjunto de subcomponentes. Reduce el acoplamiento y el trlfico de red utilizando un bean de sesion EJB ara im lementar casos de uso comunes, relacionacYos en ef lado senridor. Avuda a desacoolar comoonentes de emoresa de la i ~ p l e m e n t a c i subyaceke 6~ ocultando labliscpeda especifica de EJB y la creacion requerida a1 utllizarlos. Reduce el trlfico de red asociado a la recu eraci6n de valores relacionador desde un EJB psan!o un objeto Java serializado que contengan una lnstantinea de esos valores. Reduce el aco lamiento entre niveles de resentacion y

Presentation

Empresa

Empresa

Localizador de servicio Objeto valor

Empresa

Empresa

Delegado de empresa

empress introguciendo un proxy de nivel e p r e s e n t a c ~ h


para ocultar 10s detalles de la interaccion con el nivel de empresa.

Integration

Objeto de acceso a datos

Proporciona acceso conectable a diferentes fuentes de datos, creando una interfaz para acceso a datos que sea independiente de la fuente de datos subyacente. Esta interfaz puede entonces ser implementada por varios objetos que proporcionan acceso a fuentes especificas de datos sin requerir cambios en el c6digo que utiliza 10s datos.

Esta lista es solo una parte de la lista de 10s patrones J2EE identificados por Sun Java Center. Los patrones J2EE tambien se identifican como parte de J2EE Blueprints (http://java.sun.com/j2ee/blueprints/ design-patterns/catalog.html). Muchos de kstos son 10s mismos que 10s identificados por Sun Java Center per0 hay otros que n o lo son, como Fast-Lane Reader (descrito anteriormente en este capitulo) destinado a acelerar el acceso de s61o lectura a datos evitando el acceso basado en EJB. En el momento de escribir este libro, continuan 10s esfuerzos destinados a fusionar 10s patrones de Blueprints con 10s patrones de Java Center. Existen tambikn otras fuentes on-line que contienen patroncs de base JZEE, como T h e Server Side (http://theserverside.com/patterns/) y el sitio W e b onJava de O'Reilly (http//

La provisi6n de instancias de patrones que han demostrado funcionar en la plataforma JZEE es un gran incentivo para el disehador. Podemos aprender de la experiencia de 10s otros y ver c6mo implementan el patr6n para su situaci6n. A menudo, tambiin se proporcionan las muestras de c6digo que son especificas a1 entorno JZEE. Sin embargo, tenga cuidado. N o podemos simplementa utilizar patrones especificos de JZEE, o cualquier patr6n con ese fin ya que tendria una serie de piezas de puzzle, simplemente copiando y pegando el codigo para conseguir su sin alterar ningin c6digo. U n disehador experimentado utilizari propia so~uci6n un patr6n como guia general per0 lo adaptari para que se ajuste a1 context0 particular.
Todos 10s contextos de aplicaci6n tienen cierto grado de exclusividad, de ahi que las implementaciones de patrones deban ser adaptadas a nuestros requisitos especificos. Asirnismo, el conjunto de patrones n o

1113

Capitulo 21
cubrira seguramente el total de 10s requisitos de nuestra aplicaci6n. Debemos pensar en 10s patrones como si tuvii.ramos un conjunto de componentes de "period0 de diseiio" que pueden ser personalizados y despu& pegados con 16gica personalizada (que, en si misma, puede ser considerable) para conseguir el producto final.

A medida que analicemos las opciones para el diseiio de un nuevo sistema, la aplicaci6n de pedidos de compra en nuestro caso, se presentarin varios patrones como soluciones adecuadas para algunos de 10s problemas que encontraremos. Asi seri util examinar primero la motivaci6n y estructura de estos patrones antes de aplicarlos directamente a1 context0 de nuestro ejemplo.
En las siguientes subsecciones, definiremos todos 10s patrones de diseiio que son relevantes para nuestro ejemplo. Observe, sin embargo, que estas descripciones son introducciones bastante simplificadas. Para mis informaci6n referente a patrones de diseiio en general, 10s siguientes son recursos utiles:
O Catilogo de Patrones de Sun Java Center en http://developer.java.sun.com/developer/

technicaIArticles/J2E~patterns/
O O

Sun J2EE Blueprints en http://java.sun.com/j2ee/blueprints/design~patterns/catalog.html

Core J2EE Patterns: Best Practices and Design Strategies, de D. Alur, et al. Prentice Hall, ISBN 013-064884-1

Patron de controlador frontal


Las vistas que generan la presentaci6n para el usuario deben contener el minimo c6digo de empresa de mod0 que dicho c6digo pueda ser compartido entre multiples vistas y, asimismo, pueda ser modificado con independencia de la vista. Estos principios deben tambiin aplicarse a1 c6digo que proporciona servicios comunes para vistas y a1 codigo que proporciona flujo de trabajo y navegaci6n entre vistas. Los servicios comunes, como seguridad y gesti6n de estado, no deben ser reproducidos en multiples vistas, puesto que esto provoca problemas de mantenibilidad y cuestiones de consistencia. El flujo de trabajo asociado a parte de una aplicacion, como la secuencia de pasos que llevan a una compra on-line, es mis dificil de alterar cuando el cbdigo para controlar la navegaci6n asociada se reparte entre multiples vistas. El patr6n de Controlador Frontal introduce un componente que intercepta la solicitud del cliente y realiza una de las mis de las siguientes funciones:
O Aplica servicios comunes como autentificacibn

y control de acceso

Determina la vista apropiada para manejar la solicitud


O

Construye estado para la solicitud procesando categorias de usuario y accediendo a fuentes de datos

El siguiente diagrama muestra c6mo un controlador frontal puede mediar entre un cliente y multiples vistas. Esta mediaci6n puede formar parte de un flujo de trabajo dentro de la aplicaci6n o puede ser una opci6n basada en el lenguaje o en otros factores:

Consideraciones de disefio para aplicaciones J2EE

Controlador Frontal Solicitud Respuesta Cliente Web Servlet

/'

JSP

JSP

U n Controlador Frontal puede interactuar con otros componentes o ayudantes para proporcionar el servicio requerido. Es c o m h que un Controlador Frontal utilice un cornponente lanzador independiente que implemente cualquier flujo de trabajo requerido. Tambikn utilizari ayudantes (corno en el patr6n de Ayudante de Vista,,que verernos en breve) para realizar procesamiento especifico de empresa o para pasar estado a vistas. El s~guiente diagrama de secuencia rnuestra la interacci6n entre estos componentes:

Patron de vista de cornposicion


La mayoria de 10s sistemas de base Web consisten en rnGltiples y diferentes piginas o vistas. Cada vista consistiri en cierta funcionalidad especifica, corno una lista parcial de productos que pueden ser seleccionados en ese momento, junto con elementos comunes de navegaci61-1,de informaci6n o funcionales. Si el c6digo y formato de cada uno de esos elernentos se duplica en cada vista que lo utiliza, el

Capitulo 21
sisterna se vuelve rnuy dificil de actualizar y de rnantener puesto que cualquier arreglo y cambio debe ser '~plicado alli donde aylrezca ese cddigo y ese forrnato. C o r n o solucidn, el patrdn d e Vista de Composicicin define vnrias estrategias pnra dividir efectivamente una interfaz d e usuario cn mfiltiples sub-vistas que puede ser recombinadas para crear la vista global rcquerida. Cadn sub-vista forma un componente individual que puede mantencrse, actualizarse o retorznrse independientc~ncnte de otras sub-vistas. Un ejemplo de una pigina Web que sc ajuste nl pntrcin de vista de composici6n es el que aparece a continuaci6n. En este cnso, vemos una Vista de Cabeccra en la partc supcrior de la pantalla, vistas d e Navegacidn bajo In cabecera y en la parte inferior izquierda d e la pigina y, por w p u e s t o , la vista de C u e r p o Principal centralizada:

1 6

NPWthis month:

Early Mopter M l c e YML

New thls month: Profesvoml

C#
w w n csharpfiddf
~111

ISBN

Code

&QK&

testoassw
lBfiiP05202

-need
O t h e r W r o x sites

1ssinosas3 reb1no4los c ies1oo42~

&Qlnnlns

J.".

1861004176 I)ornlopd
Java 2 Entcmnrm Edit~on with

P.EfP&wal -

0 6 4 N q b LOQIC 5 d W e r

1e6100299e W lecloo46s6 p -

Which Java MVC (ModelView-Conboller) f r a m r w o t k do you use for S.wlrt/3SP web development?

Aunque el ejernplo rnostrado n o e s t i necesariarnente generado a partir d e plginas JSP (como sugerimos para nuestra a p k a c i 6 n d e pedido d e compra), el principio sigue siendo el mismo. La vista de composicicin
completa podria utilizar las vistas c o m o se niuestra en el siguicnte diagrama de secuencia:

Consideraciones de disetio Dara a~licaciones J2EE

Vista de Comwsicion

Puede incluirse un gestor d e vistas entre la Vista d e Coniposicion y las sub-vistas. El uso de una gestor de vistas es opcionnl, per0 resulta util si se requiere la inclusi6n condicional. A continuaci6n, una sencilla implenientaci6n d e una vista de composici6n iniplernentada c o m o una pigina JSP sin un gestor de vistas:

Patron de fachada de sesion


Si 10s EJB se utilizan sinipleniente c o m o repositorios para datos d e enipresa y sencillos servicios de empresa, entonces la mayor parte de la lcjgica d e empresa todavia residiri en el cliente que hace uso de dichos EJB. Esto resulta perjudicial p o r dos razones. En primer lugar, provocari una vez m i s un escesivo acceso n la red ( c o m o tanibikn verenios en el patron de O b j e t o Valor, niis adelante) puesto que el cliente solicita servicios d e enipresa y datos exactos. Tambikn vinculari fuerteniente al cliente con el proceso de enipresa. Esto provoca distribution y repetici6n innecesaria de c6digo entre clientes. La soluci6n es una variaci6n del patr6n d e Fachada. U n a Facliada en un objeto o componente introducido entre el cliente y un coniplejo subsistenia. La Fachada expone s61o aquellos servicios requeridob por el cliente y agrega servicios de niodo que se convierten en servicios bastos y n o finos y detallados. En t h n i n o s de patrones J2EE, una Fachada de Sesi6n desempefia este papel para la 16gica d e enipresa y 10s servicios encapsulados p o r m d t i p l e s EJB. La Fachada de Sesion, c o m o su nombre sugiere, adopta la fornia d e un EJB de sesi6n. El cliente se coniunica con la Fachada d e Sesion, que proporciona servicios de enipresa basados en o t r o s EJB conio beans de entidad.

Capitulo 21
El siguiente diagrama muestra c6mo una Fachada de Sesi6n podria controlar el acceso a nifiltiples beans de entidad y proporcionar una interfaz unifornie a un cliente. Aunque se utiliza comlinmente como un escudo para EJB de entidad subyacentes, una Fachada de Sesi6n puede acceder a servicios y datos desde otros EJB de sesi6n asi como desde Objetos de Acceso a Datos. La relaci6n entre las clases se muestra a

L
Cliente

< <EJBde Sesibn> >

-1

1..* FachadadeSesh L

1 ..* .

Objeta de Empresa

< < U B de EnI~dad z>


ObJeto de Empesa2

< <EJB de Ent~dad>>


ObJetode Empresa3

H
Objeto de Acceso a Datos

Una Fachada de Sesi6n encapsulard habitualmente la funcionalidad para uno o mis casos de uso de empresa. Puede conseguirse m6ltiples operaciones de empresa a travis de una llamada a la fachada (esto se denomina en ocasiones patr6n/locuci6n distribuida de Mitodo de Lote). En lugar de un bean de sesi6n que devuelve un grupo de Objetos Valor que deben ser tratados por el cliente, la operaci6n que el cliente desea realizar puede ser trasladada a la Fachada de Sesi6n. La iteraci6n en 10s datos tiene lugar en el servidor solo con 10s resultados pasados de vuelta a1 cliente. Esto reduce el trifico de la red, a pesar del coste de cierto sobregasto de procesamiento del servidor.

Patrdn de localizador de sewicios


En tirminos de c6dig0, el sobregasto de utilizar 10s metodos sobre una interfaz de empresa de EJB es relativamente pequeiio (simplemente el manejo de excepciones remoras). Sin embargo, la creaci6n de EJB requiere c6digo de base JNDI, especifico, para descubrir la interfaz inicial y crear el EJB requerido. Esto obliga el cliente a incluir c6digo J N D I que se encargue de la creaci6n del contexto, las blisquedas y la reducci6n de referencias. De nuevo, cualquier sofisticaci6n adicional, como cachetizar las referencias de interfaz inicial, debe ser duplicada por cada cliente. El patr6n de Localizador de Servicios define c6mo un linico objeto puede realizar las tareas de blisqueda y creaci6n asociadas a mliltiples EJB para mliltiples clientes. El cliente simplemente encuentra el Localizador de Servicios y solicita una referencia para el EJB requerido. Toda interacci6n con las interfaces inicial J N D I y EJB se delega en el Localizador de Servicios. El siguiente diagrama de secuencia muestra la interacci6n entre el cliente, el Localizador de Servicios y las implementaciones de empresa e iniciales EJB:

Consideraciones de disefio para aplicaciones J2EE

Obtener instancias

Obtener Objeto

Busqueda
I

Fadoria

1 Obtener Objeto de ~&resa I I I I

I I

Cresr un Buscar

.-

< <lnic~o EJB>>


Objetode

Ernpresa

de empresa

1
1

I I
I

I
I
I

I
I

I I

Observe que el Localizador de Servicios se implementa habitualmente con10 un semifallo con el objetivo de compartir 10s beneficios del uso de la cachC.

Patrbn de Objeto valor


Los sinlples objetos de datos expondrin normalmente sus datos como propiedades. Un cliente accederi a esas propiedades utilizando mCtodos set o get siempre que fuera necesario. El sobregasto relativamente bajo asociado a llamadas de mCtodo durante el proceso ha hecho de Csta una prdctica comlin, particularmente en entornos tip0 Integrated Development Environments (IDE) para crear interfaces de usuario basadas en JavaBeans. Sin embargo, una vez se ha introducido una red entre el cliente y el objeto de datos, esta programaci6n basada en propiedades provoca un feo efecto "diente de sierra" ya que 10s datos pasan constantemente en ambas direcciones a traves de la red. Cuando esto sucede. la comunicaci6n domina el procesamiento, la mayor parte del tiempo requerido para acceder a datos se invierte en esperar que regresen las llamadas de red y el rendimiento de la red se degrada debido a la gran cantidad de datos pasados. Esta cuesti6n puede verse a1 acceder a datos o a semicios centrados en datos expuestos por EJB. El efecto se amplifica si 10s datos se propagan a mGltiples EJB, puesto que se debe acceder a cada EJB de forma individual por la red.

Capitulo 21
O t r a considerncion a tener en cuenta nqui es la mayor parte cle 10s accesos a 10s datos t i m e c o m o objetivo la lectura en lugar de la escritura. Estos problemas pucden resolverse mediante la creaci6n de un O b j e t o Valor. El O b j e t o Valor encapsuln datos de empresa en forma d e un objeto Java ordinario en lugar d e un pesado objeto distribuido c o m o un EJB. En lugar de realizar multiples solicitudes, cadn una para una propicdad d e EJB, se emite una unica solicirud a u c dcvuelve el O b i e t o Valor. El O b i e t o Valor s e r i asa ado de vuelta al cliente, habirualmente mediante scrinlizaci6n ~ a v aEI . cliente accede entonces a las Gopiedades del O b j e t o Valor en s u espacio de direcci6n local, ahorrando asi muchas idas y venidas por la red. La relacion entre el EJB y su O b j e t o Valor

r i " ;
Objeto V a k r

La inrcraccion cntre el cliente, el EJB y el O b j e t o Valor es la siguiente:

Consideraciones de disefio para aplicaciones J2EE

E l Objeto Valor en realidad consiste en d o s instancias fkicas, una en el sewidor y otra en el cliente

Hay difercntes variacioncs que puedcn ser utilizadns dependiendo dc los requisites de la aplicClci6n. El Objcto Vnlor puedc enc.lpsular stilo parte dc los datos de empresn rcpresentados por el EJU, podria ser actualizndo con c,lmbios propagados d e vuelta a su EJB progcnitor, o el Objeto Valor poclria adoptar In forma d e un docurnento XML si se rcquiere interoperatividad distinta de Java. Los objetos valor pucden ser utilizltlos con EJB de entidad, EJB de sesion y Objetos d e Acceso n Datos nllidondc sea adccundo.

Patron de Delegado de empresa


N o es una bucna idea que los clicntes interactljcn directmnente con servicioh de cmpresa. Esto les cspone a c~mbios potenciales en In implerncnt,~cicin.Es posible encapsulnr pnrte de In internccion con servicios de cmpresa cn un ljnico EJB aplicanclo el patr6n de Fachada d c Sesi6n. Incluso asi, el cliente todavia tiene que hacerse cargo d e la blisqueda, la instanciaci6n y el rnanejo de crrores rcmotos requerido pala rnanipular un EJB. Cualquier sofisticaci6n mayor en el tratnmiento con la cnpa de empresn, corno el almacemmiento e n cnchi y agrupacion por lotes de llamndas tambi6n quecla en manos del cliente. C o m o soluci6n. un Dclcgado d c Ernprcsa ncthn c o m o unn ;ibstracci6n de lado cliente de un servicio cle cmpresa. Puedc potencialmente funcionnr directnmente con cornponentes individuales de empresa o puede .lctuar como la pnsarela dc lado clicnte a unn Fachada d e Sesi6n. El Delegado d e Ernpresa se encargari de toda la intcracci6n especifica d e EJB y proporciona una interfaz local para el cliente. Esta interfaz puede proporcionnr metodos que sinran para encapsul~rrnljltiples inter.lccioncs de servidor. El Delegndo de Empresa tanrbiin puedc nsociar cxcepciones remotas a escepciones de aplicacibn con significado. El Delegado de Ernpresa es el espacio 16gico para ejecutar el almacenamiento en cache de lado cliente de inforrnaci6n de ernpresa, como Objetos Valor, o para reintentar llnmadas f,lllidas o relevos a diferentcs servidores. La relaci6n entre el cliente, el Delegado de Ernpresa y el objeto de ernpresa es la siguiente:

Capitulo 21

Cliinte

.
1

I..*-

Delegado de Ernpresa

' F ' -l L +. .
.Buscar

y crear

r,

1 ..*

P P

--.A

Objelode Empresa

c<EJB de Enttdadzz

c c E J B de Seslbn>z

Objeto de Ernpesa2

ObJetodaEmprew3

El Localizador de Serviciosdel diagrama d e clase es o t r o patr6n que puede ser utilizado por separado o en conjunci6n con un Delegado de Ernpresa. De nuevo, la intention es ocultar las complejidades de tratar con servicios de nombrado y proporcionar una localization conveniente para aiiadir almacenamiento en cache y optimizaciones a la recuperaci6n d e referencias a objetos d e empresa y sus factorias.

Patron de Objeto de acceso a datos


Casi todas las aplicaciones utilizan datos de algun tipo. Estos datos pueden ser almacenados en diversos sitios, como bases de datos, sistemas principales, ficheros planos u otros servicios externos. El c6digo de empresa y d e interfaz d e usuario d e la aplicacidn requeriri acceso a 10s datos para ejecutar tareas para el usuario. Las tareas llevadas a cabo sobre 10s datos son normalmente indevendientes de c6mo son almacenados esos datos. Incluir c6digo especifico d e acceso a datos en la 16gica de ernpresa y d e presentation vincula ese c6dicro . , a una fuente esvecifica d e datos. Esto reduce la flexibilidad de la soluci6n puesto que el c6digo requerirj. cambiar sie~npre que cambie la fuente de datos. Los cambios efectuados la fuentes de datos subyacente puede incluir un cambio d e base d e datos (Servidor S Q L a Oracle, por ejemplo) o carnbios al modelo global como migrar desde el acceso a datos basado en JDBC a acceso a travis de EJB d e entidad. La soluci6n consiste e n proporcionar un Objeto de Acceso a Datos ( D A O ) para abstraer el acceso a 10s datos. EL D A O encapsular6 el c6digo requerido para localizar y acceder a la fuente de datos. Toda la 16gica de empresa o d e presentaci6n utilizarj. el D A O para recuperar y almacenar datos como se muestra a continuaci6n:
-.

--

nte de ~ a t ~ ;

Consideraciones de disefio para aplicaciones J2EE


La interfaz de DAO define la rehcidn entre la lbgica de empresa o de presentacidn y 10s datos. Si el mecanisrno de localizacidn subyacente y de almacenamiento utilizado para acceder a 10s datos cambia, puede crearse un nuevo DAO para acceder a 61. Puesto que el DAO tiene una interfaz fija para sus clientes, Csta no requeriri ningfin cambio en la 16gica de empresa o de presentacidn, como se muestra a

continuation:

i I

utiliza

encapsulado
base de datos Sybase

La verdadera implementacidn del DAO variari dependiendo del contexto. Si el cliente es una JSP, el DAO puede ser una clase Java ordinaria, un servlet o un EJB. Si el cliente es un EJB, entonces es probable que el DAO sea una clase ordinaria Java o posiblemente otro EJB.

Patron de Ayudante de vista


Una inadecuada divisi6n entre mecanismos de presentacibn y lbgica de empresa desemboca en sistemas inflexibles y costes crecientes de mantenimiento. El uso de piginas JSP para interfaces de usuario de base Web es un ejemplo fundamental, ya que es ficil incluir demasiado cbdigo Java en la JSP. Si este cddigo adopta la forma de 16gica de empresa, entonces esto sirve para aumentar el acoplamiento entre ldgica de presentacidn y ldgica de empresa, que es perjudicial para la flexibilidad. Bien sea el cddigo de empresa o de presentacibn, la inclusidn de grandes cantidades de c6digo Java en una JSP significa que no puede ser mantenida y adaptada hicamente por diseiiadores Web. Tambi6n provoca potencialmente la repeticidn de cbdigo en distintas piginas JSP. Utilizando el patrdn de Ayudante de Vista, el cddigo Java es encapsulado en clases de ayuda, como JavaBeans o etiquetas personalizadas. La vista delega el procesamiento de empresa o de presentacidn en el objeto ayudante. En el caso de una JSP, elimina el cddigo de la JSP y permite a 10s diseiiadores Web interactuar con 61 mediante el uso de etiquetas JSP estindar o personalizados. A continuaci6n, se muestra una tipica interacci6n de secuencia:

Capitulo 21

0
Observe cbnio, en este caso, la vista simpleniente instancia el avudante v obtiene 10s datos de 61. Si el ayudante es implementado como un ~ a v a ~ c auna n , JSP puede &ceder a ia funcionalidad requerida a travks de las etiquetas e s t i n d a r u s e ~ e a n ygetproperty. En este caso, el ayudantc accede a la funcionalidad d e ernpresa; sin embargo, 10s Ayudantc d e Vista tarnbiin pueden scr utilizados para encnpsular procesarniento d e presentaci6n o estado temporal.

Patron de Vista de lanzador


Este patr6n sugiere un mod0 de combinar 10s patrones de Controlador Frontal y d e Ayudante dc Vista con el objetivo d e crear unn soluci6n integrada para 10s problcrnas a 10s que se enfrentan. Estos problemas incluyen ldgica d e ernpresa repetida y dispersa, la necesidad dc separar flujo d e trabajo d e presentaci6n y la necesidad d e imponer servicios comunes como la autentificaciAn. El patr6n de Vista d e Lanzador es una cornbinacion de un Controlador Frontal y mhltiples vistaa y Ayudantes de Vistas. A diferencia del patron de Servicio al Trabajador (que analizarenios a continuacicin), en 1.1 Vista de Lanzador el Controlador Frontal y el lanzador n o instancian Ayudantes de Vista y utilizan sus datos para deterrninar la vista d e destino. Cualquier seleccibn de este tipo se realizari basindose en inforrnaci6n d e la solicitud del usuario. Cuando se propaga la solicitud a la vista, 10s Ayudantes d e Vista apropiados serin instanciados y accederin a 10s datos requeridos por la vista. La relaci6n entre las diferentes clases es tal y c o m o se muestra en esta figura:
c <JSP> r
1

Cliente

1
7

Controlador Frontal

Lanzador

1I..*.

Vista -

,,* .

Ayudante

C o m o puede ver, en este rnodelo todos 10s accesos a datos esternos tienen lugar solo despuks de acceder a la vista.

Consideraciones de disefio para aplicaciones J2EE


Patron de Servicio al trabajador
Este patr6n sugiere un nlodo d e combinar 10s patrones d e Controlador Frontal y Ayudante de Vista con el objetivo d e crcar una solucicjn integrada para 10s problemas a 10s que se enfrenta. Estos problemas incluyen 16gica d e empresa repetida y dispersa, la necesidnd de separar flujo de trabajo de presentacibn y la necesidad de imponer servicios comunes con10 autentific~ci6n. El patr6n de Servicio al Trabajndor esti bahado en un Controlador Frontal. El Controlador Frontal delega el acceso a datob en Ayudantes de Vihtd, que son creados y poblados antes d e acceder a la vista. U n I.~nzador,que forma parte del Controlador Central, decide quC vista nlostrar al cliente y propaga la solicitud junto con 10s Ayudantes d e Vista. La relacicjn entre Ins diferentes clases se muestra a

< <JSP> r
Vista

1
1

I
I

I
1
Ayudante Avud

1
I..*I..*

LAprincipal diferencia entre este patrcin y el de Vista de Lanzador es que Servicio al Trabajador es m i s pro pi ado alli donde se requiere procesamiento frontal. El Controlador Frontal y el lanzador interactlian con 10s Ayudantes de Vista antes de reenviar la solicitud a la vista. Por ejemplo, en Servicio al Trabajador, algunos de 10s datos recuperados pueden en realidad controlar la viata a la que se lanza la solicitud.

Patron de Manejador de lista de valores (Iterador pirgina-a-pagina)


Al acceder a grandes cantidades de datos, el cliente debe intentar evitar repetidas solicitudes de red para acceder a cada objeto de datos sucesivamente. Este sencillo uso de objetos remotos que encapsulan datos, como EJB de entidad, por ejemplo, pueden ser muy ineficientes en tC-rminos de uso de recursos d e red y de servidor. El Manejador de Lista d e Valores se implemente comirnmente como un bean de sesi6n con estado que consulta fuentes d e datos subyacentes para obtener 10s datos requeridos. La fuente de datos podria ser una base de datos, un conjunto d e EJB de entidad o cualquier otra fuente de datos encapsulados como un Objeto de Acceso a Datos. Los datos serin almacenados en la memoria caches y despueh proporcionados nl cliente al ser solicitados. La relaci6n entre un cliente Web, un Manejador de Lista de Valores y un conjunto de EJB d e entidad subyacentes es la siguiente:

Capitulo 21

lor de 4 laloreg
.-

'

--

--

I
I

Nivel Web

I I

El patron de Manejador de Lista de Valores generari Objetos Valor para representar 10s datos subyacentes. Estos Objetos Valor se guardarin en cache y ofrecidos de vuelta al cliente al ser solicitados. El cliente puede controlar el nlirnero de Objetos Valor devueltos en una vez a travks de la interfaz iteradora. Las relaciones entre las clases irnplicadas se rnuestran en el siguiente diagrarna de clases:

Lista de Valores

I ) proporciona datos

-El
Objeto Valor

El diagrama de secuencia tiene este aspecto:

--"
Consideraciones de diset7o para aplicaciones J2EE
Obtener datos -&llect~on> Obtener pr6x1mo subconjunto

4-

- - -- ---

I I I
I

I I I I
I

I I
I

Observe que este patron es denominado Manejador d e Lista d e Valores en el catilogo d e Patrones JZEE de Sun Java Center per0 que, Blueprints JZEE de Sun, aparece como Iterador Plgina-a-Plginn.

Patron de Lector de via rapida


Aunque 10s EJB de entidad son un potente mecanisrno para acceso concurrente a datos y persistencia, son bnatante pesados para enumerar grandes cantidades d e datos. Tomando el ejemplo de enumeration de datos e n un catilogo, el requisito habitual consiste en obtener datos d e solo lectura para navegar. Asimismo, 10s datos subyacentes cambiarin con poca frecuencia y n o es esencial que cualquier instantdnea de datos refleje el Gltirno estado absoluto de 10s datos. Acceder a estos a travks de metodos buscadores de EJB tendrd como resultado la creaci6n de muchos EJB para poco trabajo de utilidad. Esto supone un gran sobregasto en una situacibn en la que la velocidnd es normalmente el factor clave en la utilidad d e la aplicacibn.

La solucion es evitar 10s EJB d e entidad asociados a 10s datos y acceder a 10s datos de forma m i s directa a travks d e un O b j e t o d e Acceso a Datos. U n D A O d e este tipo encapsularia normalmente acceso a base de datos, por lo que, efectivamente, 10s datos proceden directamente de la base de datos. Esto provocaria un mayor rendirniento sin deseatabilizar la aplicacibn.
El Lector de Via Rdpida puede irnplementarse como un DAO o como un EJB de Sesion que acttie c o m o m a Fachada de Sesi6n para DAO. La relacion entre el cliente y el Lector d e Via Rdpida es la siguiente:

Capitulo 2 1

7
Lector de Via Ra id

A h a , armados con los detalles de fondo d e estos p.itroncs de disciio, podcmos comcnznr con continnza el anilisih del principio de nuestra .iplicaci6n de orden de compm, nnturalmente con una lista de productos.

ut~liza para actualizar

\r""

E l

Objeto de Empresa

Comenzar por el principio


Debelnos comenznr el esamcn del sistcma por algun lugar, asi quc vamos a empeznr con lo primer0 que necesita cl usuario: 10s productos catalogaclos. Puesto que el sistema d e pedidos d e compra debe scr utilizado c o m o parte de una Intranct, necesitaremos proporcionarle una interfnz HTML. Pnra gcnernr el H T M L rcquerido, la interfaz de usuario, como la funcionnlidad del catilogo de productos, podria ser implernentada como un conjunto de JavaSenrer Pages (piginas JSP) o d e servlets. D e las dos tecnologias, las piginas JSP s o n m i s adecuadas para la g e n e r a c i h d e HTML, por lo que la interfaz de usuario parn Flujo d e Trabajo d e Pedidos (Ordering Workflow) y Flujo dc Trnbnjo de Aprobacicin (Approvnl Workflow) del sistema de pedidos de compra (rernitase a nuestro diagrama U M L original) consistiri en gran medida en un conjunto d e pjginas JSP. Sin embargo, 10s servlets tambikn desemperiarin un pnpcl importante en la provision de servicios cornunes y en el control del flujo tle trabajo p m estas p x t e s dcl sistemn. Observe que lo siguiente n o e s un anilisis sobre el m o d o en que, en realidad, funcionan 10s servlets y piginas JSP, puesto que ya hemos dado suficiente cobertura a estos ternas en capitulos antcriores. En su lugar, se revisarin cicrtos nspcctos de cstns tecnologias dcsde el punto de vista del cliseno.

Presentacion de datos del producto al usuario


Podernos csplorar algunas de 12s principales cuestiones de disefio de JSP y de servlets considerando c6mo podrian irnplernentarse ciertns partes dcl Flujo de Trabajo de Pedidos. Al catnlogar productos para su selection por parte del usuario, el uso d e una o niis piginas JSP podria funcionar. Los datos del producto pueden obtenerse directamente desde la basc de datos a travbs d e JDBC. Esta sencilla arquitectur~ cs la que mostramos J continuaci6n:

Consideraciones de diseiio para aplicaciones J2EE

JSP

reserva de conexiones

Base de datos

lncluso en esta sencilla etapa, pueden tomarse decisiones de diseiio para crear un sistema m i s flexible y mantenible. U n aspecto es el uso de las reservas de conesiones d e bases de datos para contribuir a la capacidad de reajustabilidad cornpartiendo de un modo rnis efectivo las conesiones d e bases de datos entre piginas JSP o servlets quc Ins utilicen. La cuestidn de la reajustabilidad y el reciclaje de recursos seanalizarj. rnis adelante en cste capitulo. El acceso a 10s datos de producto se requeriri probablernente desde el interior piginas JSP. La5 piginas JSP facilitan relativamente la combinaci6n del diserio visual d e interfaces de usuario con el c6digo Java requerido para extraer 10s datos de producto de la base de datos. Si retrocedernos un momento, podemos definir algunos principios d e guia que pueden beneficiar este sencillo diseiio:
1-1 Abstraer el acceso a datoh

3 Distinguir entre funcionalidad y presentaci6n


3

Separar el control de la interacci6n de usuario de la presentacibn y el manejo de datos

Examinemos cada uno d e estos puntos por separado.

Abstraer el acceso a datos


De andisis previos sobre patrones de disefio J2EE hemos aprendido que, en casos en 10s que un componente recupera datos, pueden obtenerse beneficios utilizando un Objeto d e Acceso a Datos ( D A O ) para abstraer la fuente de datos subyacente. Si n o sabemos si la fuente de datos subyacente cambiari con el tiempo, un D A O aporta mucha flesibilidad. Por ejemplo, en el caso del sistema de pedidos de compra, la implementaci6n inicial del catilogo puede conllevar el acceso direct0 a la fuente de datos a trav6s de JDBC. A medida que evoluciona el sistema, el uso de fuentes de datos de terceros puede requerir el uso de EJB o d e x c e s o basado en senicios Web. Si deben incorporarse mdtiples catilogos de proveedores, el cddigo asociado d e empresa y d e presentaci6n puede convertirse ripidamente en un desorden de instrucciones cabo. El uso de un D A O permite aiiadir nuevas fuentes d e datos de un modo relativamente inofensivo. Los inconvenientes de utilizar un D A O son dos:
3 Casi cualquier forma de abstracci6n conlleva fases y manejo de datos extra. Esto significa que el

rendirniento puede verse afectado. Se requiere inicialmente m l s esfuerzo en diseiio y en c6digo para implementar en D A O . Igual que sucede con cualquier decisi6n d e disefio, siempre hay una concesi6n. Tendri que decidir si las ventajas de flesibilidad y mantenibilidad de un D A O pesan m i s que la cantidad que esfuerzo inicial extra

Capitulo 2 1
rcquerido y la reduccidn potencial del rendimiento. Puesto que el sistema de pedidos de compra abarca a mdtiples proveedores, casi con toda probabilidad merceria la pena realizar este tip0 de inversion importante.

Distinguir entre funcionalidad y presentacion


El principal dogma de disefio para piginas JSP es elirninar la mayor cantidad de c6digo posible de las piginas. Esta separaci6n de la presentaci6n y el c6digo tiene rnuchas ventajas, tales corno:
2
U

El c6digo cornGn puede ser cornpartido por mGhiples piginas, proporcionando servicios comunes y reduciendo en esfuerzo de mantenimiento La reduccicin o eliminaci6n del c6digo facilitari la vida a1 diseiiador de piginas Web sin c6digo c6digo para ser editados

3 La mayoria de 10s cambios en el funcionarniento del c6digo no requeriri las piginas que utilicen ese

Esto garantiza que cualquier uso de las piginas JSP rnis all; de las formas rnis sencillas irnplicari esta distinci6n entre HTML y codigo Java. La separaci6n puede tornar diversas formas, incluido:

a El c6digo para la pigina puede ser encapsulado en alguna forma de componente Java siguiendo el
patron de Ayudante de.Vista

u Las piginas Web que comparten elementos cornunes de funcionalidad, de information o de navegacion pueden ser construidas a partir de un conjunto de cornponentes comunes siguiendo el
patr6n de Vista de Cornposici6n El uao del patron de Ayudante de Vista reduce la cantidad de c6digo necesario en las piginas JSP que proporcionarin la presentacion para el Flujo de Trabajo de Pedidos y el Flujo de Trabajo de Aprobaci6n en nuestro sisterna de pedidos de cornpra. Que 10s ayudantes sena JavaBeans o etiquetas personalizadas depender6 del contest0 especifico en el que se necesite un ayudante. Puede que se decida utilizar un estilo de ayudante, corno JavaBeans, de forma consistente para contribuir a la mantenibilidad o a la cornpatibilidad descendente, Es conveniente seiialar que 10s patrones integrarin y utilizarin otros patrones. Por ejemplo, dada la decisi6n anterior de utilizar D A O en el sistema de pedidos de compra, siempre que el c6digo de la implementaci6n del Ayudante de Vista necesite acceder a datos, utilizari el D A O adecuado. Este tip0 de relacibn es tipica de un lenguaje d e patrbn, en lugar d e ser solamente una lista de patrones. Los patrones de u n lenguaje d e patrones mantienen s d i d a s relaciones. Cada patr6n resuelve problemas concretos dcntro &I sistema y dele@ funcionalidad e n implementaciones para otros patrones siempre y cuando sea apropiado. D e nuevo, n o se trata Bnicarnente d e cxtraer una soluci6n a partir d e un puzzle de patrones, sin0 que ciertos patrones funcionan bien juntos y se encuentran comfinmente desempeiiando funciones similares en sisternas similares. La interfaz de usuario de Flujo de Trabajo de Pedidos p de Flujo de Trabajo de Aprobaci6n consistiri en piginas HTML, o vistas, que contengan catilogos dc productos y forrnularios que debe cumplimentar el usuario. La usabilidad de un sistema quc, contenga mdtiples vistas se ve reforzada en gran medida proporcionindole un nivel de consistencia en estilo y contenido (por ejemplo, posicion y contenido consistentes de una barra de navegaci6n). En una interfaz de usuario de este tipo, h a b d ciertas partes consistentes de la pantalla del usuario rnientras que el resto varia dependiendo del contexto, como ir desde la vista detallada del product0 hasta vista del pedido de compra completo.

Consideraciones de disefio para aplicaciones J2EE


Este estilo d e interfaz d e usuario puede alcanzarse aplicando el patr6n de Vista de Composition para romper sub-vistas coniunes, c o m o cabeceras y navegaci6n, y volver a combinarlas con contenido especifico de vistas. Aden& de proporcionar consistencia para el usuario, la Vista d e Conlposici6n facilita el niantenimiento y desarrollo del sistema. C o n i o ejemplo, la navegaci6n en todas las vistas existentes puede ser actualizada simplemente actualizando la sub-vista de navegaci6n compartida. Igualmente, la creaci6n de una vista nueva se simplifica puesto que sus partes de mayor tamafio pueden ser estraidas de plantilla. Unn variaci6n a destacar aqui consiste en que algunas partes del Flujo d e Trabajo d e Aprobaci6n pueden estar destinadas inicamente a gestores (con10 cifras sobre niveles actuales de presupuesto del departamento). E n este caso, la Vista de Composici6n proporciona estrategias que implican a gestores de vistas que puedcn actuar como filtros sobre la presentaci6n del contenido. Por ello, un gestor puede ver diferente contenido en una pigina de registro de pedido que un usuario nienos privilegiado.

Separar interaccion de usuario, presentacion y datos


Estrategias corno el Ayudante d e Vistas proporcionan u n rnodo conveniente de separar 16gica de ernpresa d e 16gica d e presentacibn. Si embargo, cierta 16gica de aplicaci6n funciona mejor al ser procesada antes de acceder a la vista. C o m o sugieren sus nombres, Flujo de Trabajo de Pedidos y Flujo de Trabajo de Aprobaci6n requieren ambas una secuencia de pasos que deben ponerse en prictica para guiar al usuario a travCs de 10s procesos de pedido y aprobaci6n. Si se pierde un paso, puede perderse informacidn vital, dando lugar a u n pedido incorrecto.

L Isccuenciaci6n d e tales pasos puede construirse en las vistas. Cada vista tendria vinculos hacia las vistas
posterior y anterior en el flujo de trabajo. Sin embargo, esto da lugar a un flujo de trabajo muy fdgil que no puede alterarse ficilmente. La soluci6n es separar el flujo d e trabajo de la vista, rnanteniendo cada vista independiente en su lugar e n el flujo d e trabajo y atiadiendo el potencial para reutilizacion d e vistas. Podernos considerar al Ayudante del Vistas corno un m o d 0 de separar el flujo de trabajo, per0 la cuesti6n clave aquies que estas decisiones de flujo de trabajo necesitan tomarse antes de que se acceda a la vista. Se necesita un mecanismo que intercepte la solicitud del usuario, que determine ddnde se encuentra el usuario en el flujo de trabajo actual y que lo lance entonces a la vista apropiada. Para llevar a cabo este tipo d e procesaniiento previo, podemos introducir un servlet para que actue como Controlador Frontal, tal y c o m o se define en el patr6n de Controlador Frontal, analizado anteriormente. El Controlador Frontal es habitualmcnte un sewlet cuya linica tarea en la vida es procesar information de entrada de usuario (en ocasiones Ilamada gestos de usuario). El s e n l e t n o contiene c6digo para generar salida para el usuario; en su lugar, captura datos procedentes del usuario, 10s procesa y decide qu6 vista debe ser mostrada a1 usuario. En t6rminos de aplicaci6n de orden de compra, el Controlador Frontal es el lugar ideal para albergar procesamiento comun tipo autentificacibn. La autentificacion es particularmente iniportante puesto que tanto la presentaci6n como la aprobaci6n d e pedidos d e cornpra depende firrneniente de autentificar la identidad del usuario. C o n i o henios niencionado anteriorrnente, algunas de las Vistas de Composici6n del Flujo d c Trabajo d e Aprobaci6n quizis s61o muestren cierta informaci6n a los gestores. Es por lo tanto esencial que la autentificacibn siempre se lleve a cabo antes de acceder a las vistas (observe que esto n o significa que el usuario tenga que registrase antes de cada vista d e pigina; sirnpleniente significa que se comprueban las credenciales para algunos formularies. Esto puede adoptar In forma d e un cuco de autentificacibn pasado desde el navegador del usuario). El Controlador Frontal es el lugar ideal para afiadir estos servicios comunes.

Capitulo 21
U n sistema puede tener m6ltiples Controladores Frontales. En el caso de nuestro sistema de pedidos d e compra, habrd como minimo dos: u n o para el Flujo de Trabajo d e Pedidos y otro para el Flujo de Trabajo de Aprobaci6n. Estos Controladores Frontales proporcionardn flujo de trabajo durante la creaci6n y aprobaci6n de pedidos de compra. Para garantizar que el c6digo de autentificaci6n (y cualquier o t r o servicio comun) es compartido por 10s Controladores Frontales y son reimplementados cada vez, el Controlador Frontal puede delegar la aplicaci6n d e tales servicios e n otros objetos o componentes. El Controlador Frontal tambiCn puede realizar procesamiento ndicional que construya estado, utilizndo por 1.1 vista a la que se reenvin la solicitud. Este estado es pnsado como objetos de ayuda. Un Controlador Frontal que utiliza objetos ayudantes es parte de una via hacia la arquitectura de Controlador de Vista dc Modelo (MVC) popularizada por Smalltalk y utilizada en m a forma niodificadn en In Clases de Fundacibn Java (JFC). El Controlador Frontal contiene el conocimiento de lo que deberin suceder en un punto determinado del tiempo en respuesta a un gesto de usuario. La,Vista refleja el estado de estn parte del sistema a1 usuario. La parte final de la ecuaci6n es el Modelo. Esta es 1.1 pnrte de datos del sistema. La vistn hace referencia al modelo para recuperar 10s datos que debe niostrar al usuario. El controlador alterari el estado y 10s contenidos del niodelo de forma apropiada basindose en 13 entrada de usuario. La siguiente figura muestrn c6mo priginas JSP, servlets y JavaBcans pueden ser utilizados para crear un modelo que reparte responsabilidades del mismu mod0 que MVC:

L7s clases dc Ayudantes de Vista que conformnn el modelo pueden ser sencillas representaciones de datos recuperados por el Controlador Frontal. Alternativamente, estas clases pueden encapsular el acceso a datos para esta parte del sistema. Los dntos representados pueden ser recogidos de la solicitud del cliente o recupcrados desde una fuente de datos cn el servidor. El precis0 equilibrio de responsabilidades entre el Controlador Frontal, 10s Ayudnntes de Vistas y Ins vistas variari dependiendo de la cantidad de recupcracibn de datos necesaria y de si la solicitud puede ser encaminada sin que otros datos sean recuperados. Dos "macro-patrones" que son descritos en cl cntdlogo de Patrones J2EE de Sun Java Center, Servicio a Trabajador y Vista de Lanzador, analizan conlo pueden compartirse estas

Consideraciones de disetio para aplicaciones J2EE


responsabilidades. Aunque estos patrones han sido presentados anteriormcntc en este capitulo, merece la pena csaminar su documentation completa para llevar a cabo un esamen m i s eshaustivo.

Existe un grim debate sobre la idoneidad tiel paradigma MVC conro meta'fora para sistemas de base Web. Gran parte de este debate gira alreciedor de la incapacidad de actualizar la vista del usuario directarnente en respuesta a canrbios err el nrodelo, pcresto que no hay mode de "l7acerlos bajar" a1 navegarlor. Sin embilrgo, si ccrrnple rrn propdsito adecrrado a la hora rle analizar la separrrcidn de roles. Para otms opciones, cornprcrebe 10s arcbivos de las listas de correo rle Patrones J 2 E E (j2eepa tterns-interest@java.sun. corn). Java Pet Store que se adjunta a J2EE Blueprints ofrece crn enfoque interes'rnte. Permite qrre 10s conrponentes del nivel de presentaciiin, cotno delegados de ernpresa, registrerr su interis en cleterrinados nrodelos de datos co)r una instancia de clase local llawada ModelMa nager. Los nrodelos residen en el nivel EJB. En lugar de configurar urr sistenra de eventos clistribuido, cacia ~rccidn liigica presentada a l f l u ~ o de trabajo en el nivel EJB devolvera' urra lista de 10s modelor que ha actcralizado. La instancia ModelManagrr infornrara' entonces a 10s escrrcbantes apropiados en el ni,uel de prcsentacidn de estos cambios y ejto garantiza que 10s clelegados de enrpresa del nivel de presentacion estardn actrrcrlizcdos la prdxirnil .vez que se renueve fa vista.

Evolucion del sistema


Cualquiera que sea el equilibrio en la implementation, una nrquitectura que gira alrededor de 10s patrones d e Controlador Frontal, d e Ayudantc de Vistas y d e Objeto d e Acceso a Datos nos ofrece algunas vcntajas dignas de menci6n. Los cambios en el flujo de trabajo n o requeririan necesariamente cambios en la vista o en modelo. D e un moclo similar, 10s cambios en el mccanismo de acceso a datos pucdcn hacerse transpnrentes a la vista y al controlador. Esta triple separacibn nos ofrece un gran numero dc opciones, en caso de que se precisaran cambios en el estilo o en In localization dc la interfaz d e usuario. Puesto que la separacibn resultnnte de responsabilidndes se ajusta ampliamente a1 modelo MVC, si el cliente tiene que volver n ser implementado como unn IU Swing, el rnodelo (en f o r m de JnvaBeans) podria seguir siendo el mismo y simplemente ser resituado en el clicnte. Si la I6gica de flujo de trabajo del controlador fuera implernentndn como una clase indepcndiente del servlet, Pste tambien seria ficilmente relocalizablc. Alternnrivamente, podria crcarsc un proxy para ser utilizado en el cliente que asociarin la entrada Swing n 10s gestos apropiados de usuario esperndos por el controlador de JSP/servlet. La vista podria entonces ser sustituida por una que generara XML en lugar de HTML. El prosy del clicnte podria entonces utilizar esta salida para actualizar su tnodelo local. Hay, por supuesto, un pequeiio problema con una d e las estratcgias sugeridas anteriormentc. Traslndar el modelo a1 cliente n o es la sencilla tarea que algunas herramientas le harian creer que es. Si nuestro modelo esti accediendo a In base de datos a travks d e J D B C o d e EJB, traslndar esta funcionalidad desde el servidor nl cliente acarrea algunas cuestiones serias de rendimiento, conec!ividad y seguridad. D e hecho, incluso el traslndo de scrvidor a servidor puede provocar tales problemas. Este es sblo un punto surgido al examinar un modelo basado en JavaBeans. Si estuvi6ramos crcando una aplicncion que tuvicra que ser altamentc reajustable, entonces esta arquitectura demostraria, por lo general, cstar por debajo del nivel bptimo. Albergar estado en el servidor en nombre de un cliente es un asunto espinoso. En estc caso, el modelo contcndrh dntos que ocupan memoria fisicn y (potencialrnente) una conexion J D B C a la base de dntos subyacente a travks d e la cual pueda rcnovar sus contenidos. Por una serie de motivos, sencillamente no es reajustable. Considere las siguientes cuestiones asociadas a esta situacion:
3

Para resolver 10s problemas d e mernoria, puede que sea posiblc scguir aiiadiendo m6s ~nernoria. A rnedid.1 que se alcance el limitc de la memoria fisica del hardwarc. puede aiiadirse o t r o scnridor para

Capitulo 21
manejar algunos de 10s clientes. El problerna inmediato es que entonces quedamos bloqueados entre clientes y servidores. Un senridor concreto albergari el nlodelo para un cliente concreto. Esto puede funcionar potencialmente frente a estrategias de equilibria de c a r p utilizadas por el sistema.
3 La memoria fisica es s61o uno de 10s recursos utilizados por una aplicaci6n. En el caso del modelo,

tambiCn requiere una conexi6n a base de datos para acceder a sus datos subyacentes. Mientras que la memoria puede ser relativarnente barata, las licencias de bases de datos tienden a no serlo. Si cada modelo alberga uno de estos recursos, se agotarin con bastante rapidez. Si debe crear uno cada vez que necesite renovar o actualizar sus datos, se deteriorari el rendimiento. El uso de recursos reservados, como reservas de conexiones JDBC, puede ayudar a aliviar algunos de estos problemas, igual que puede hacerlo un enfoque apropiado frente a la gesti6n de estado, como verenlos mis adelante. Si ya ha leido 10s capitulos anteriores sobre EJB, probablemente sabri a d6nde nos lleva esto. Para conseguir verdadera reajustabilidad para la mayoria de aplicaciones JZEE, debe introducir EJB en la arquitectura, como mostramos a reserva de conexiones
JDBC
-k
--

Base de datos
.--

Y
" * '

:4--

JSP

RMI

C
-

RMI

reserva de conexiones
J DBC

Base de datos

Blueprints J2EE reconoce que algunas aplicaciones comenzarin a partir de una sencilla base HTMLIJSP y despuks evolucionarin a medida que cambien 10s requisitos del sistema. De hecho, proporcionan lo que se podria considerar un modelo de madurez para aplicaciones J2EE de base Web, como se muestra en la siguiente tabla: Tipo de Aplicaci6n Tecnologias Piginas HTML Piginas HTML, piginas JSP, servlets Complejidad Muy poca Poca Funcionalidad Muy poca Pocn Solidez Mucha Poca

Piginas HTML

Consideraciones de diseAo para aplicaciones J2EE

T i p o d e Aplicaci6n Pdginas JSP con componentes modulares

Tecnologias

Complejidad

Funcionalidad Media

Solidez Media

Piginas H T M L , Media plginas JSP, servlets componentes JavaBeans, etlquetas personalizados Piginas HTML, Mucha piginas JSP, servlets componentes JavaBeans, etiquetas personalizados, Enterprise Java eans

Piginas JSP con cornponentes modulares y Enterprise JavaBeans

Mucha

fa"ti11aSp

Este modelo a c t h c o m o una buena regla bisica a la hora de considerar qu6 tecnologias se precisarin para implementar una determinada aplicaci6n. Sin embargo, sea consciente de que tendrl sus excepciones. Algunas aplicaciones muy reajustables pueden construirse sencillamente con sewlets siempre que utilice 10s productos de servidor adecuados.

Anadir el nivel media


Volviendo al tema de nuestro ejemplo, vemos que nuestro sistema se ha expandido u n poco porque el estado que utiliza reside ahora en el nivel medio de un EJB. Esto nos presenta varias cuestiones nuevas d e diserio que debemos tratar:
U i Q u e tipo d e EJB debemos utilizar para proporcionar acceso a datos? iDebemos modelar la base

de datos con10 u n EJB de entidad o debemos utilizar un EJB de sesi6n y lanzar desde alli consultas S Q L a la base d e datos? Las ventajas e inconvenientes de 10s diferentes tipos de EJB ya han sido analizados. Ahora es necesario que consideremos c6mo se aplicarian mejor en el contexto de nuestra aplicacion. i C b m o interactlian 10s componentes del nivel de presentacidn con el EJB? Esto es especialmente importante si 10s datos son modelados como una entidad. Aunque estamos obteniendo reajustabilidad y flexibilidad al utilizar EJB, estamos incurriendo potencialmente en un considerable sobregasto de comunicacidn. Piense de nuevo en la aplicacidn utilizada con10 contexto para esta consideracibn de diseiio. C o m o primer paso, q ~ ~ e r r i a n modelar ~os nuestros datos d e Producto con10 EJB d e entidad. Esto significaria que podriamos aprovechar la Persistencia Gestionada p o r Contenedor (CMP) para ahorrarnos d e escribir cierto c6digo J D B C )r permitir al contenedor optimizar el acceso a datos. Nuestros componentes del nivel de presentacibn utilizarian entonces la interfaz inicial d e la entidad para buscar ~ r o d u c t o apropiados s para su presentacibn basindose e n las preferencias del usuario. El peligro inmediato aqui es que esto degenerari e n un delirio d e programacidn enemiga de la red y basada en propiedades. Para superar esta situaci6n. puede aplicarse el patron de Objeto Valor alli donde se obtengan mliltiples propiedades a la vez. Por ello, en lugar de que la JSP interactlie con el EJB Producto para obtener cada propiedad individualmente, la JSP puede realizar una linica llamada al EJB para obtener P r o d u c t V a l u e O b j e c t , que contendria toda la informaci6n requerida por la JSP para mostrar esa informaci6n del product0 al cliente. TambiCn puede encontrar este patron en algunos sitios bajo el nombre de Atributos Combinados.

Capitulo 2 1
Apl~c.lrel O b j e t o Valor para crear un P r o d u c t V a l u e O b ] e c t nos proporcionarb cierta cantidad de optimizaci6n. Sin embargo, el efecto "diente d e sierra" que ya hemos mencionndo rcapareceria r.ipidamentc si el nivcl W e b debiera ncccder repetidamente n rnilltiplcs EJB de entidad Product aolicitando a cadn uno dc cllos su P r o d u c t V a l u e O b i e c t . Esiste una necesidnd aoui de solicitar rnultivles obietos valor en una vez. U n a C o l e c c i o n dc Objetos Valor puede ser entonces devuelta en una (mica respuesta, reduciendo el sobreensto d e red. El Patr6n d e Maneindor dc Lista de Valores define estrntegins varn devolver colecciones " de Objctos Valor n clientcs. El P r o d u c t L i s t e r e n el sistema de pedidos de compra puede aplicar este patrcin para entregar colecciones de P r o d u c t V a l u r O b j e c t s alas piginas JSP que conforman el Flujo d e Trabajo d e Pedidos. El cliente \Web pucde ajustar el numero de Objctos Valor devueltos dependicndo del tamatio dc In pigina HTML.
u
A

Los dntos de producto en cl sistema de pedidos de compra son tipicos d e datos de catilogo porque son en su mayoria d e s61o lectura y su cambio es lento. En casos con10 Cste, el uso de EJB d c entidad para el acceso puede imponer un sobregasto indebido cn la funcionalidad cle busqueda. Podcrnos aplicar el patrbn de Lector de Via Ripida para acelernr el acceso n datos en grupo utilizando un objeto independicnte para proporcionar acceso de d o lectura directanientc a la fuente d e datos (evitando la capa de EJB dc entidad). Esto accleraria el acceso a1 catilogo en la mayoria d e 10s cnsos con nlgfin coste adicional de desarrollo y un pcqueno numento en la complejidad de la aplicacihn. Sin embargo, la decisi6n de aplicnr el patrhn de Lector dc Vin Ripida depende de si el rendinliento que obtiene de un Manejador d e Lista d e Valores en cachh es suficicnte para sus necesidades. En esencia, se trata d e una lucha entre In velocidad y la sencillez. O t r a cuestibn a tener en cuenta a la hora de utiliznr un Objeto Valor es el de In interoperatividad. En la situaci6n Java-a-Java, es ficil pasar ehtos objetos serializados a travCs d e una interfaz RiiI. Sin embargo, si cualquiern d e sus clientes es potencialmente un cliente CORBA, entonces esta interfaz estd potencialmcnte fuera d e 10s limites para cllos. Incluso si el Object Request Broker (ORB) cliente implen~enta In funcionalidad de objetos-por-valor requerida por C O R B A 3, todavia implica que sc necesita rnis esfuerzo el bean en el cliente. En este caso, puede que sea mejor utilizar una a la hora de leer (rrnnznnhal~n~) representacibn de base XML para que el objeto valor lo consiga en la plataforma. P r o d u c t V a l u e O b j e c t no necesita contener el c o n i ~ m t o completo de datos en el Producto. C o m o regla general, 10s datos en bean5 de este tip0 deben ser d e s61o lectura. Puesto que representa una instantdnea de los d ~ t o spuede , haber valor linlitado e n incluir datos voldtiles en el Objeto Valor. Si, por ejemplo, el EJB Producto contuviera el nivel actual de existencias para ese producto, puede que n o fuera relevante para ser incluidc) cn P r o d u c t V a l u e O b j e c t puesto que ehta informacidn podria estaranticuada en el momento dc su uso. Esta informaci6n debe ser recuperada "fresca" d e P r o d u c t o cuando sea necesaria. La Gltima afirmacibn sugiere otra cuestibn. Se considera una prictica errdnea que 10s clientes (clientes de aplicacihn o servlets/plginas JSP) accedan directamente a EJB de entidad. C o m o hemos visto, esto tiende a provocar accesos muy detallados a Ias propiedades d e EJB y acopla a1 cliente m i s intimamente a la implementaci6n d e la lbgica d e empresa y 10s datos. Lo que necesitamos hacer es desacoplar el cliente del detalle de la implementaci6n de la capa de empresn. Esto puede conseguirse aplicando el patr6n de Fachada de Sesi6n. El bean de sesi6n servird para abstraer la estructura del EJB Producto solamente proporcionando acceso a la funcionalidad requerida por el cliente. En el caso del Producto EJB, la intenci6n principal d e esta fachada es ocultar la estructura de datos del mismo EJB Producto. Una Fachada de Sesihn puede, de hecho, ser utilizada para ocultar un subsistema de empresa completo y presentar al cliente una interfaz simplificada.
La cuesti6n final relacionada con el P r o d u c t o es si debe renlmente ser ?lodelado como una entidad. En la situaci6n actual, los clientes estin utilizando un Manejador de Lista de Valores (o Lector de Via Ripida) y una Fachada de Sesi6n para acceder a los datos d e entidad. { N o seria mejor que accediiran~os directamente a la base d e datos desde estos beans d e sesibn (como hariamos d e todas formas si eligiiramos el Lector de Via Rdpida) y nos olvidiramos de utilizar un bean d e entidad? D e hecho, el uso de colecciones de Objeto Valor podria evitarse pasando de vuelta los R o w s e t s recibidos de las consultas de la base d e datos. R o w s e t s (conjuntos d e filas) fueron introducidos en J D B C 2.0 como un m o d 0 c6modo de representar

Consideraciones de diseho para aplicaciones J2EE


datos tabulares. Un Rowset aparece conio JavaBean y puede utilizarse micntras se esti desconectado de In base de datos. TambiCn es Serializable por lo que puede pasarse en una llaniada dc tnitodo RMI. Aunque puede resultar muy l i d en ciertas circunstancias, pasar un Rowset noes conipatible con crear nietodos de tipo seguro. Si un rnCtodo toma o devuelve un Rowset, Cste realmente represent3 un tipo dc datos opaco (no hay notificacion sobre la forrna que deberian adoptar 10s datos). Cualquirr Rowset recuperado de una tabla podrb pasarse a un rnitodo de ebte tipo. Esto podria causar errores inPditos durante el procesa~nientodel Rowset. De un mod0 similar, un campo en un Rowset esti potencialmentc nils abierto a interpretaciones incorrectas quc una propiedad de un JavaBean, o que un eleniento o atributo en XML. Pasar datos en un Rowset refleja el uso estendido de Recordset en ActiveX Data Objects (ADO) en aplicaciones de Microsoft Windows. En ambos casos, tiende n bloquear In arquitectura en una tecnologia y a crear dcpendencias frigiles entre el tormato dc los datos y los usudrios progranilticos de 10s datos. Esto afecta seriarnente a la flesibilidad de aplicaciirn frente a1 cambio. N o existen respuestas correctas o incorrectas e n cuanto a1 uso de entidades frente a objetos de acceso a datos o el uso d e Rowsets frente a tipos de datos especificos. Yo, personalmente, me inclinaria por abstraccion frente a acceso directo, a menos que haya serios problemas de velocidad con la aplicaci6n. El uso responsable de la abstraccion aumentari la flexibilidad y mantenibilidad de la aplicaci6n. Tradicionalmente, gran cantidad de coste y del sufrimiento del desarrollador asociados a una aplicaci6n llega despuis del desarrollo inicial, asi que cualquier cosa que simplifique el mantenimiento de la aplicaci6n debe ser bienvenida.

A pesar de esto, gran parte dependeri del origen de los datos, de la eficiencia de la base de datos, de la cficiencia del contenedor EJB, de si 10s datos de la entidad son utilizados por mliltiples beans en la grada EJB y de la cantidad de exceso de comunicaci6n entre el contenedor EJB y la base dc datos. Dos grandes tiene funcionalidad asociada, adem.is de datos, y si factores determinantes aqui son si un ~ r o d u c t o necesita transacciones. Si un ~ r o d u c t o es simplemente la asociacion de una linica fila de base de datos, debe preguntar si es suficientemente tosco para ser un bean de entidad. De nuevo, afortunadamente, esta prcgunta no tiene una respuesta fija. Las entidades sencillas de datos funcionan bien en algunas situaciones y no en otras. En tCrminos de tnnsacciones, 10s beans de entidad proporcionarin control de transacci6n sobre 10s datos de forma independiente de la base de datos. Sin embargo, si 10s datos de nuestro bean ~roducto no pueden ser actualizados, entonces no hay necesidad de apoyo de transacciones. Asi, por cjernplo, la decisidn sobre si incluir o no el nivel de existencias en la clase product en nuestro modelo de UML seria aqui muy importante.

De compras
Ahora quc podenios catalogar 10s productos, necesitamos realmente hacer algo litil, como permitir al usuario hacer alghn pedido. Crear un pedido de compras tiene asociado un deterrninado flujo de trabajo:
3 O

Identificar al usuario Mostrar el catllogo de productos a1 usuario Permitir al usuario seleccionar uno o m6s productos del catilogo Enviar el pedido de compra completo a1 gestor adecuado

Esto tendri iteraciones y otras condiciones pero, de nuevo, captura la esencia de lo que intentarnos hacer. Este flujo de trabajo esti encapsulado por OrderingWorkflow en nuestro diagrarna original dc clase ULM del sistema de pedidos de compra.

Capitulo 21

Encapsular el flujo de trabajo de pedidos


El Flujo de Trabajo d e Pedidos, es decir, la interacci6n real con 10s objetos de empresa, podria implementarse en la grada Web o en la grada de empresa. Implementar el flujo d e trabajo en el nivel Web significa que la 16gica d e empresa e s t i muy acoplada al cddigo d e interfaz d e usuario. Si la misma ldgica de empresa fuera requerida por otra parte del sistema, tendria que volver a ser implementada. Si el flujo de trabajo es implementado en un EJB de sesi6n, esto desacopla la ldgica de empresa d e la grada de presentaci6n y la convierte en reutilizable y reernplazable. Para un sistema d e grandes dimensiones, como nuestro sistema Acme, otra ventaja d e utilizar un EJB de sesi6n sin estado en lugar de un servlet es el mayor grado de reajustabilidad al utilizar este tipo de componente. Por lo tanto, el Flujo d e Trabajo d e Pedidos se convierte en un EJB de sesidn que oculta la implernentacidn d e la 16gica d e empresa. Puede interactuar con otros EJB de sesi611, EJB de entidad y Objetos de Acceso a Datos. Si esto le suena, es porque esti actuando como una Fachada d e Sesi6n. La Fachada de Sesidn para el Flujo d e Trabajo d e Pedidos es m i s sofisticada que la que oculta el EJB de entidad de Producto. Proporcionari un conjunto d e mktodos, como addLineItemToPurchaseOrder, por ejemplo, que encapsulen una operacidn 16gica de empresa para el cliente. El cliente no se preocupa de cuintas bases de datos u objetos se utilizan para llevar a cabo esta tarea en el nivel d e empresa. Encapsular el Flujo d e Trabajo en u n EJB de sesidn elirnina complejidad del cliente. Sin embargo, el cliente debe todavia contener c6digo para buscar e instanciar el EJB. Invocar mitodos en el EJB puede provocar RemoteException y el cliente debe capturar la excepcibn o reintentar la operaci6n. Seria mejor agrupar toda esta funcionalidad en un lugar d e m o d 0 que la interaction de manejo con la grada de empresa se convirticra en responsabilidad de una clase. El patr6n de Delegado de Empresa ofrece una estrategia para esta opernci6n. El Delegado de Empresa puede ocultar el uso de Objetos Valor y guardarlos en cache para reducir el tr6fico de red. T o d o esto beneficiaria a nuestra aplicacibn distribuida en tCrnminos d e rendimiento y mayor sencillez del cddigo cliente. C o m o ya hemos mencionado, una ventaja de utilizar un Delegado de Empresa es la capacidad d e asociar excepciones remotas a excepciones con significado para el cliente. U n principio general a la hora de disefiar interfaces de objeto y de componente es que deben generar excepciones con significado (por ejemplo, B u d g e t L i m i t E x c e e d e d , P r o d u c t N o t F o u n d ) en h g a r de simplemente propagar las d e nivel inferior ( R e m o t e E x c e p t i o n , A r rayIndexOutOfBoundException). El Delegadode Empresa puede desempeiiar una funcidn Gtil e n esta estratificaci6n de excepciones d e m o d o que pueden capturar o manejar una escepcibn desde un servidor o generar una excepci6n que tenga sentido para sus clientes, como mostramos a continuation:

Base d e datos E"cepcibn ecupada, intbntelc I--, TooManyLocks I I I

: :
!

----..-

. -

I I

I I

lnterfaz d e nivel inferior

lnterfaz d e ni

Teniendo en cuenta que existe una Fachada d e Sesidn para el Flujo de Trabajo de Pedidos, podemos decidir que n o s e requiere u n Delegado de Empresa. D e nuevo, esiste un intercambio entre la cantidad de trabajo requerida para implementar y las ventajas derivadas. En este caso, el argument0 principal para utilizar un Delegado de Emprcsa seria climinar el cddigo EJB de busqueda y tle creacidn del cliente. Corno tal, podria aplicarse el patron d c Localizador d e Servicios para ofrecer esta abstracci6n sin forzar todo el acceso a tmvks del Delegado d e Empresa.

Consideraciones de diselio Dara a~licaciones J2EE


El elemento clave es que cl Delegado de Empresa y la Fachada de Sesidn se encargan del flujo de trabajo de enipresa (la secuencia de pasos 16gicos para llevar a cabo una tarea de enipresa). Desde la perspectiva de la interfaz de usuario, el lanzador del Controlador Frontal controla 10s pasos dados en la interfaz de usuario para introducir informaci6n y toma decisiones relacionadas con la tarea de empresa global. El lanzador controla la vista que se ha de niostrar a continuaci6n. Es importante distinguir entre estos dos flujos. Los gestos de usuario capturados por el Controlador Frontal pueden corresponderse de forma exacta con las tareas de empresa y cadi uno puede traducirse en un evento lhgico asociados y pasado a la Fachada d e Sesi6n. Alternativamente, puede tomar mdtiples interacciones d e interfaz d e usuario antes de que se invoque un m i t o d o de empresa. Es iniportante distinguir entre estos dos flujos d e trabajo. El andisis del diagrama completo de clase UMLniostrari que la c h s e o r d e r i n g ~ o r klfo w utiliza una clase session p x a albergar el estado del cliente, como 10s contenidos del carro de la compra. Cualquiera que haya trabajado con piginas JSP o servlets reconoceri inmediatamente este concept0 procedente del objeto sesi6n integrado proporcionado por el API del sewlet. Sin embargo, aqui debenios tener cuidado. La clase remesenfa el conceDto de una sesi6n v n o necesariamente se asocia a una inivlenientaci6n de sesi6n de sendet. Al annlizar previamente el albergue de estado en el servidor, hemos destacado varias cuestiones sobre de memoria. el reciclaie de recursos v la almacenar estado d e este mod0 es~ecifico del cliente. La eesti6n " elusion d e bloqueos del sewidor son tareaa m i s dificiles en el contenedor Web que en el contenedor EJB. Puesto que el contenedor EJB tiene un mecanismo definido de reciclaje y persistencia para el estado de cornponenres, 10s recursos utilizados para el carro de la compra serin gestionados de forma m i s eficiente en la grada EJB q u e e n la grada Web. Utilizar un EJB de sesi6n para la funcionalidad del carro de la compra es tambikn m i s flexible en el sentido en que puede ser utilizado por clientes dotados e infradotados.

Modelos con estado versus modelos sin estado


Puesto que ahora estamos trabajando potencialrnente con varios beans de sesibn, merece la pena desviarse clel tema principal para tratar consideraciones referentes a modelos con estado frente a rnodelos sin estado. En el modelo con estado, una instancia d e componente de lado servidor e s t i dedicada a u n cliente concreto y alberga sus datos en almacenes temporales para un ficil acceso. En el modelo sin estado, n o hay una instancia dedicada d e componente de lado servidor para el cliente y todos 10s datos deben ser recuperados desde almacenaniientos persistentes. La elecci6n entre componentes d e lado servidor sin estado o con estado es el tema d e muchos debates y discusiones. Aunque el niodelo sin estado es indiscutibleniente reajustable, conlleva sobregastos relacionados con al almacenamiento y recuperation de estado para cada acceso d e cliente. El modelo con estado n o tiene tales sobregastos per0 su reajustabilidad depende por completo de reservas efectivas y algoritmos de activaci6n/pasivacicjn proporcionados por el contenedor EJB. Los EJB con estado tambiin presentan un reto frente al fallo. U n EJB sin estado puede dar el relevo a otra instancia de contenedor con s61o una pequefia cantidad de pirdida potencial de datos. Si un EJB de sesi6n con estado ha albergado el estado conversacional y kste se pierde, el usuario puede que tenga que empezar de nuevo su transacci6n. Adenias de requerir rnis transferencia de datos, el niodelo sin estado tambien requiere m i s trabajo por parte del disefiador de la aplicacih cliente, puesto que siempre debe ser notificado q u i estado utilizar. Esto afecta a nuestra eleccion de bean de sesi6n para implementar la funcionalidad en las clases OrderingWorkf lowy ~ r o d u c t ~ i s t e r . Ty a c1o m o estin las cosas, el t r a b a j o d e ~ r o d u c t ~ i s t e r e s enteraniente sin estado; se presenta con una categoria y cataloga el product0 en sus interior. Segdn la prictica adecuada, 10s reaultados serian devueltos como una colecci6n de Objetos Valor que n o dejan estado en el servidor. P o r ello, esto sugeriria que P r o d u c t L i s t e r funcionaria bien conio bean d e sesibn sin estado. Sin embargo, para obtener 10s beneficios del uso d e la cachi y la eficacia el uso del patron d e Manejador d e Lista d e Valores, un bean d e sesi6n con estado seria m i s apropiado. Remitase a la descripcion original del patron d e Manejador de Lista de Valores e n 10s patrones de Sun Java Center para un debate m i s detallado d e este tema.

O r d e r i n q W o r k f l o w debe tener cierto concept0 de estado para comprender d6nde e s t i el cliente en ese momento e n el proceso de pcdido. Esto plantea una cuesti6n clnve de disetio sobre d6nde debe .~lrnacenarse el estado, con el cliente, en el EJB o en una base de datos:
setv~dorEJB
JSP

Base de d a m

1
I

4 -

C.dn unn tle 1.1s opciones tiene ventajas e inconvenientes:


-1 Estado e n el cliente

El cliente debc pasar el estado n cadn Ilnmada de mCtodo que lo necesite. Esto perrnite In esistencia de EJB sin estado y ofrece reajustabilidad a todos 10s contenedorcs EJB. Sin embargo. pone m i s pcso sobrc el clientc y In red y puede provocar un riesgo d e seguridad si se hace A travks de cucos pnra clientes infradotados. En algunos casos, la politica de seguridad de lado servidor incapacitari el uso dc cucos. precisnndo el uso de reescriturn de U R L o de campos ocultos. Ninguno d e estos rnecanismos es realtnente adecuado para albergar cualquier gran cantidad d c estado. Cunlquier forma d c cstado albergado por el cliente tan1bii.n sirve pnra complicnr el diserio de la interfaz rernota dc un EJB.
-1 Estado e n

el EJB Utilizando un EJB d c sesiGn con estado, cl estado requerido puede ser cargado o adquirido con el tiempo. Esto simplifica el dibetio de una intcrfaz remota de EJB y nligera la carga sobre el cliente y In red. Sin embargo, reduce 1.1 capacidnd del servidor EJB para reutilizar beans y puede tambien provocar que el cliente qucde bloqucado e n un servidor, frustrando el equilibria de cargas.

Si el sistenla dcbe npoyar clientes infradotadob, entonces deben proporcionnrbe alguno\ metodo5 dostin~dos a asociar cl cliente con el EJB apropiado. El cliente es cntonces utilizado con un cuco que identifica el EJB que contiene su estado. Esta asociaci6n debe ser n~ancjadn por uno de los componentes del nivel d e presentacibn.
-1 Estado e n u n a base d e datos

El cstado para un EJB sin estado puede scr almacenado en una base de datos. El clientc es entonces ernitidv con un cuco o identificndor que identifica el estado ( n o r n d m e n t e la clnve prirnarin del registro que contiene cl estado cn In bdse de dntos). Esto afectn en menor medida al disefio d e la interfaz que nlbergar el estado en el cliente per0 tiene cierto impact0 en la carga de la rcd y en la complcjidad del cliente. Sin embargo, si nlantiene la reajustabilidad garantizada de una implementnci6n sin estado a cambio de 1119s tiempo dedicado a buscar y recuperar 10s datos de la base de datos. Recuerde, sin embargo, que utilizar el cache de la base d e datos o modelar el cstado corno un bean d e entidad podria reducir este tiempo considerablerncnte. El tbrmino "base d e dntos" en rcdidad aqui hace rcferencia a cualquier repositorio de lndo servidor, idealnlente uno transaccional. Sin embargo, si el estado no csti destinado a ser persistente, el alnxlcenamiento aiternativo, como un servicio de directorio adaptado a J N D I , funcionaria bien. Los requisitos d e renjustabilidad y rendimicnto desernpefiarin un arnplio papel en la decisi6n referente al alberguc del estndo. Una vez se h a y determinado la locnlizaci6n del estado, esta decisi6n afectari al disetio dc In interhz remota para el EJB de sesi6n.

Consideraciones de diselio para aplicaciones J2EE

Presentar el pedido
U n a vez que el usuario ha p r o g r e d o en el tlujo de trabajo para la selecci6n dcl producto, estari preparado para presentar su ordcn de compra completnd.~para su aprobaci6n. La cLue O r d e r P r o c e s s (de nuevo, remitase nl diagr.~maU M L ) tendria varias responsnbilidades para comprobar el pedido. Ademis de compl-obar !,I validez dcl pedido, debe tambien coniprobar si el d e p n r t x n e n t o tiene suficicnte presupuesto para tal pedido o puede comprobar si a ese usuario concreto be le perniite r e a l i z u pcdidos d e compra d e ese valor. La clase o r d e r p r o c e s s podria ser ~mplementada c o m o un bean d e sesi6n sin estado q u e un proceso linico d e ernpresn sobre el estado q u e le ha sido pasado, o podria pasar a forniar yarte d e una implernentaci6n del flujo d e trabajo d e pedidos si es in~plementada corno u n bean d e sesi6n c o n estado. U n a vez que o r d e r p r o c e s s estP satisfecha c o n el yedido, debe enviarlo para su aprobaci6n. En este punto, surge un asunto importante en diseno distribuido. El gestor del usuario debe aprobar el pedido, per0 n o cs posible incluir al gestor en el sistema. En este nioniento, el sisterna se cowierte en asincrono yuesto que n o hay ningun gestor nl que el proceso de cornprn puede entregar una solicitud de aprobaci6n sincrona. En su lugar, el pcdido de compra debe ser capturado y alniacenado, en espern de quc el gestor puedn exnrninarlo y aprobnrlo.

Elegir un mecanismo asincrono


T o d x Ins interacciones que henios tratndo hasta cl mornento (RMI y H T T P ) han sido sincronns en nnturnleza. La arquitectura para este requisito asincrono tendrj. que utilizar una tecnologia o enfoque difercntc. El mecanismo utilizndo depender5 de la estrechez tlel acoplamiento entre el siste~na d e yedidos y el sistema de nprobnci6n. Se sugieren tres posibilidades:
J E-mail

LJaplicaci6n poclria utilizar el API JavaMail para enviar al gestor un e-mail que contenga el pedido de compra. Esto seria muy flexible para el gestor puesto que incluso podria aprobar cl pedido dcsde su cuenta d e correo d e base Web rnientras se encuentra fuera d e la oficina. Sin embargo, presenta m i s cuestiones referentes al procesamiento de la ayrobaci6n o rcchazo del pedido. En prlnier lugar, la aylicaci6n debe poder controlar la respuesta al e-mail y proccsarla cuando Ilegue. La informaci6n d e pedido de compra dcbe haber sido presentada al gestor en forma legible. Para recuyerar la inforrnaci6n original del pedido, la aplicaci6n debe analizar el mensaje de e-mail para toda la informaci6n del pedido o debe, como minirno, recuperar alguna forma dc identificador del pedido. U n identificador de pedido haria referencia a 103 datos del pedido original almaccnados en alg6n lugar en una base de datos. I'ara proporcionar autentificaci6n, el gcstor tendria quc utiliznr u n certificado digital para firmar el e-mail dc rcspuesta.
Esta soluc16n ofrecc un buen alcance (es decir, 5610 requiere que el gestor tenga un cliente e-mail para renlizar la aprobaci6n) y e s t i muy debilmente acoplado. Sin embargo, es algo improductivo y p o t e n c d m e n t c Inseguro.
U Base d e datos

El pcdido podria ser al~nacenado en una base d e datos dentro del sistema. El gestor tendria entonceb que acceder a cierta forrna d e aplicaci6n que consultnra la base de datos en busca d e pedidos a IJ espera de la aprobacidn dcl gestor. El gestor interactuaria entonces con esa aplicaci6n para aprobar o rechazar 10s yedidos. Puesto que toda la inforrnaci6n e s t i almacenada en una base d e datos, n o habria ningun yroblema en manejar un valor de retorno como con e- nail. Sin embargo, seria yreciso cierta forma dc indicar que el pedido ha sido aprobado o rechazado, como un indicador en la base d e datos o trasl.~dindoloa otra tabla. Se proporcionaria seguridad nutcntificando al gestor antes de que utilizarn la aplicnci6n.

Capitulo 21
Esta soluci6n tiene menos alcance puesto que enlaza dos partes de la apkaci6n a una base de datos corndn (aunque puede que esto se requiera de cualquier forrna para acceder a informacibn presupuestaria y del producto). Esto supone rnis responsabilidad para el gestor, puesto que deberi acceder a 10s datos en la base de datos, incluso si su llegada es notificada via e-mail. TarnbiCn esti estrecharnente acoplado a la representacibn dcl pedido. Sin embargo, todo sc lleva a cabo dentro de un dorninio corndn de seguridad y significa que el desarrollador no tiene que tratar esplicitamente con algunos de 10s puntos negativos de las cornunicaciones asincronas (que analizaremos mas adelante).
9 Sewicio d e mensajeria

Podriamos utilizar Java Message Service (JMS) para enviar un rnensaje asincrono al gestor a travks d e un sisterna d e rnensajes dedicado. Este rnensaje esperaria en una cola apropiada hasta que pudiera ser entregado ( o recuperado) por la aplicacibn de aprobacibn. Puesto que el mensaje no pretende ser legible, podria ser codificado convenienternente cotno X M L o como un JavaBean serializado. Seria m6s conveniente utilizar el bean serializado para soluciones Java integrales, per0 XML es niis flexible y contribuye a la integracibn.
L , ? llegada de la funcionalidad XML Data Binding (JAXB) debe convertir a XML en una mejor opcibn, como rnuestra esquernlticarnentc el siguiente diagrarna:

Pedido de comora

XML Data Binding

enviar

recibir Analizar Pedido de


XML

Serv~dord e cola

Una vez que el pedido ha sido aprobado o rechazado, podria ser trasladado a una cola especifica "aprobado" o "rechazado". La eleccibn de diseiio aqui esti entre el estado del pedido de cornpra indic'ldo por su ubicacjon (es decir, la cola en la que se encuentra) o en un indicador en el niisrno mensaje. Las colas transaccionadas deben ser utilizadas para garantizar que n i n g h rnensaje queda olvidado si fallara la operacion por cualquier rnotivo. Estas realizan la elimination del rnensaje d e una cola y su alrnacenarniento en otra parte de la transacci6n. Una vez en la cola adecuada, el pedido d e cornpra estaria disponible para un posterior procesarniento, que implicaria ser pasado a otra aplicaci6n, corno la un proveedor externo. Esta solucion tiene un alcance considerable puesto que 10s mensajes pueden potencialmente cruzar fronteras entre organizaciones. El formato flexible del rnensaje proporciona un reducido acoplamiento entre las aplicaciones y la seguridad se incluye con10 parte del sistema de rnensajeria. Una desventaja es que, aunque la rnayoria de 10s desarrolladores J2EE estln familiarizados con el uso de EJB, servlets y RMI, son menos lo que estln familiarizados con JMS por l o que les llevaiia algun tiernpo aprender un nuevo API y paradigma de prograrnaci6n. Los API Java para Mensajeria XML (JAXM) tarnbikn prometen facilitar esta forma de interacci6n entre aplicaciones pasando mensajes de base S O A P , eliminando potencialmente la necesidad de acceder a colas directaniente.

Consideraciones de diseiio para aplicaciones J2EE


Una carga titil X M L puede tambie'n ser utilizada corno un mensaje de e-mail para proporcionar u n sistema de mensajeria afin a Internet a1 ser utilizado con almacenes de mensajes orientados a la aplicacio'n. En este caso, una aplicacio'n tendria que recuperar el mensaje del almac6n y presentar su contenido a1 gestor, probablemente a la manera del servlet que proporciona una interfaz de base Web. Esto elimina la inmediatez de enviar el mensaje directamente el gestor, pero lo hace mucho ma's pra'ctico.
De nuevo, el requisito preciso de la aplicaci6n controlaria las fuerzas en estas decisiones. Puesto que el sistema de pedidos de compra se distribuiriapotencialmente por el planeta, es probable que la soluci6n de mensajeria basada en JMS con mensajes codificados en XML fuera mis eficiente. Esto equilibra la facilidad de procesarniento, las caracteristicas de integraci6n y el alcance potencialrnente rnundial de 10s sitios rernotos de Acme Corporation.

Reajustabilidad y disponibilidad a traves de la asincronicidad


Corno hernos visto, el rnargen de tiempo entre la presentaci6n del pedido de cornpra y su aprobaci6n o rechazo por parte del gestor puede ser rnuy amplio (cuesti6n de semanas si estin de vacaciones). Aunque esto es potencialmente aceptable para el sistema de pedidos de compra, seria inaceptable para un escaparate de cornercio electr6nico. De hecho, para el tipico sistema transaccional de comercio electr6nic0, un retraso en el pedido de minutos o incluso de decirnas de segundo durante el procesarniento del pedido del usuario puede provocar atrasos y pantallas de "sisterna ocupado". Por este motivo, incluso algunos aspectos que podrian considerarse intuitivarnente corno sincronos pueden ser ejecutados de forrna asincrona. Tornernos el procesarniento de una tarjeta de credito on-line corno ejernplo. Puesto que la tarjeta de credito debe ser cornprobada y aprobada por un procesador de tarjetas de credit0 (norrnalmente una cornpaiiia tercera), esta llarnada de aprobaci6n puede ser encolada para una entrega posterior. Las llarnadas pueden realizarse en lote o cuando el sistema tenga capacidad de sobra. Por el lado positivo, esto puede rnejorar enorrnernente el rendirniento y reajustabilidad del sisterna puesto que implica esperas. El h i c o inconveniente verdadero es para cualquier titular de una tarjeta de credit0 cuya verificaci6n falla. En este caso, deben ser inforrnados posteriormente (habitualrnente via email) de que su transacci6n no ha podido ser procesada. La mensajeria es tarnbikn una herrarnienta titi1 en 10s mornentos en 10s que el servidor de destino no esti disponible, ya sea por accidente (fallo del servidor), diseiio (rnantenirniento) o sobrecarga debida a1 acceso de dernasiados usuarios. El cliente puede entregar rnensajes a la cola y estos quedarin ahi hasta que el servidor regrese. De este rnodo, aporta cierto nivel de solidez a la aplicaci6n dificil de alcanzar al utilizar exclusivarnente rnecanisrno asincronos.

Cuestiones relacionadas con sistemas asincronos


Corno hernos visto, utilizar sisternas asincronos de operaci6n y de rnensajeria tiene algunas ventajas. Tarnbien tiene, sin embargo, ciertos inconvenientes. Si se necesita salida, ernisor y receptor deben estar de acuerdo en que el resultado sea enviado a una determinada cola. Tarnbien deben estar de acuerdo en un identificador para el rnensaje concreto a1 que responde. Finalrnente, el ernisor del mensaje original debe escuchar la llegada de rnensajes o exarninar la cola para esperar la llegada de su respuesta. Otra cuesti6n es que las transacciones necesitan una gesti6n especial cuando alcanzan las fronteras asincronas. La transacci6n asincrona no puede propagarse con el rnensaje, por lo que se requiere cierta forma de alrnacenamiento de estado de transacci6n. Aunque esto tiene mucho sentido (las transacciones sincronas deben completarse con la mayor rapidez), significa que un fallo en el rnanejo se hace rnis cornplejo y que se requieren otros rnecanisrnos para informar del fallo a1 usuario del sistema. En el caso de la tarjeta de cridito, el pedido debe ser cancelado y se debe enviar un mensaje de e-mail al usuario. Ambas acciones tienen lugar fuera del alcance de la transacci6n asincrona dentro de la cual el usuario solicita sus articulos.

Capitulo 21
TambiCn resulta mis dificil obtener un valor de retorno del procesamiento asincrono. Aunque la mayoria de sistemas de mensajeria proporcionan un modo de obtener un acuse de entrega del mensaje, 10s mensajes son en gran medida un mecanismo de una sola trayectoria. Si se requiere un valor de retorno, se requiere tambikn una ruta de vuelta independiente (es decir, otra cola) entre servidor y cliente. Establecer interfaces entre sistemas de mensajeria y EJB ha supuesto tradicionalmente un problema. Sin embargo, en J2EE 1.3 y versiones posteriores, puede utilizarse un EJB controlado por mensaje como recipiente direct0 para una cola o apartado de mensajes. Los mensajes recibidos pueden ser procesados o reenviados a EJB ordinarios de entidad o de sesion con el EJB controlado por mensaje desempefiando la funci6n de un adaptador. Con anterioridad a J2EE 1.3, un objeto adaptador que implementa la interfaz JMS Message Listener tenia que ser registrado como recipiente de 10s mensajes. Este adaptador reenvia entonces 10s mensajes a1 EJB apropiado utilizando las llamadas de interfaz asincrona normales. Aunque no esti tratado aqui, la entrega de mensajes a EJB anteriores a J2EE 1.3, asi como el uso de EJB controlados por mensaje como adaptadores, se analiza con detalle en la documentaci6n original para el patrdn de Activador de Servicio del catilogo de Patrones J2EE de Sun Java Center.

Aprobar el pedido
Volviendo a nuestro sistema de pedidos de compra,ApprovalWorkf l o w y A p p r o v a l P r o c e s s son anilogas a O r d e r i n g W o r k f l o w y O r d e r P r o c e s s . Estin sujetas a muchas de ]as mismas fuerzas en su diserio y, por ello, serian implementadas por lo general del mismo modo, como A p p r o v a l W o r k f l o w siendo una Fachada de Sesi6n. Una importante diferencia es que s61o hay un tip0 de datos manejados ( O r d e r s ) . Todos 10s datos con 10s que se trabaja serin procesados por esta parte de la aplicaci6n. N o existen datos estiticos como el catilogo de productos. Otra diferencia es que el flujo de trabajo asociado a la aceptaci6n o rechazo de un pedido es lineal. N o hay una fase independiente de iteration como la existente a1 cargar el carro de la compra seguido por la presentacidn del pedido. Debido a estos factores, la funcionalidad d e ~ ~ ~ r o v a l ~ r oincluye c e s sel control de 10s datos utilizados durante la aprobaci6n. Para facilitar esta tarea, cuenta con un mCtodo para enumerar 10s pedidos de compra que esperan la aprobaci6n del gestor. Esto simplifica la forma de esta parte del sistema. La clase A c c o u n t utilizada en el proceso de aprobaci6n comprobaria cualquier solicitud contraria a 10s limites y reglas del departamento para asegurar que el gestor se ajusta, por ejemplo, a su saldo miximo. A c c o u n t seria modelada como un EJB de entidad. Esto es justificable puesto que A c c o u n t contiene 16gica de empresa y datos. El saldo de fondos procedentes de la cuenta del departamento seria acoplados a la aprobaci6n del pedido. En un sistema mis acoplado, el proceso de aprobaci6n tambikn reduciria el nivel de existencias de cada product0 albergado en una base de datos. En ambos casos, A c c o u n t formari parte de una transaction puesto que el cargo s6lo debe tener lugar si el pedido es aprobado (es decir, trasladado a la cola "aprobado"). La necesidad de una transacci6n para el proceso de aprobaci6n podria ser normalmente identificada desde el caso de uso asociado durante el modelado del sistema:
1. El gestor se registra en el sistema de aprobaci6n 2. Se muestra a1 gestor la lista de pedidos de compra en espera de su aprobaci6n

3. El gestor selecciona un pedido de compra y analiza 10s detalles


4. El gestor aprueba el pedido de compra 5. El sistema carga en la cuenta del departamento la cantidad derivada del pedido de compra

6. El sistema reenvia el pedido de compra para su cumplimiento

Consideraciones de diseho para aplicaciones J2EE


Las alternativas aqui serian que el usuario rechazara el pedido de compra, que fallara el saldo o que fallara el reenvio del pedido de compra. Los pasos 5 y 6 sugieren una relacion transaccional entre ellos por ello, cuando Sean asociados a1 dominio de la solucion: se indicara que requieren una transaccion. En tirminos de clase, el metodo a p r o v e ( ) d e ~ ~ p r o v a l ~ r o cnecesitaria ess ser marcado c o m o transaccional a1 igual . uso de colas de mensaje transaccionales garantizarian que el q u e el mCtodo d e b i t ( ) d e ~ c c o u n t El movimiento del pedido de compra entre las colas "pendiente" y "aprobado" forman una operation atomica con el saldo. La clave para las transacciones es mantenerlas tan cortas como sea posible. N o es necesario que t o d o el procesarniento llevado a cab0 por A p p r o v a l W o r k f l o w o A p p r o v a l P r o c e s s sea transaccional. D e hecho, esto ralentizarian innecesariamente el sistema. El objetivo primordial de las transacciones es mantener la integridad de 10s datos. Esto requiere que 10s cambios Sean aislados entre si y se consigue esencialmente bloqueando algunos de 10s datos subyacentes. C u i n t o s m i s datos e s t i n bloqueados, mas probable s e r i que otras transacciones tengan que esperar a que se libere el bloqueo.

Aunque puede jugar mucho con 10s niveles de aislamiento, el limite esti en que cuintas rnis transacciones utilice, rnis competencia tendri para 10s recursos. De esto se desprenden plazos agotados y usuarios frustrados. La linica soluci6n real a esto consiste en mantener las transacciones lo rnis cortas posibles. Por ello, s61o debe utilizar transacciones alli donde sean necesarias y asegurarse de que 10s mitodos transaccionales no realizan demasiado procesamiento innecesario. Las transacciones cortas y el r5pido reciclaje de recursos son 10s dos factores fundamentales en la reajustabilidad de grada media.
Merece la pena continuar p o r u n m o m e n t o con el reciclaje de recursos. Se trata de u n concept0 importante en todos 10s niveles. Si cuenta con una cantidad infinita de recursos, entonces n o importa c u i n t o tiempo espera u n componente a una instancia concreta de recurso puesto que otros componentes pueden recuperar una instancia de la reserva infinita. A medida q u e desciende el numero de instancias de recursos, la cantidad de tiempo que u n componente espera a 10s recursos es m i s critica. Esta relacion puede representarse e n el siguiente diagrama:

lnfinito

Tan larga como desee

A
Ntjmero de recursos

4
Fraccibn de tiempo

v
Uno
4

v
Wan corta como sea posible

La mayoria de las aplicaciones compiten p o r rnis de un recurso per0 sigue siendo importante reciclar recursos tan ripido c o m o sea posible para contribuir a la reajustabilidad. El modelo J2EE para EJB e s t i disefiado para contribuir a la reajustabilidad, pasivando EJB cuando n o son necesarios y devolviCndolos a O S la reserva de objetos. Puesto que son pasivizados, pueden liberar 10s recursos que albergan y ~ S ~ se ponen a disposition de otras instancias que sirven a otros clientes. Sin embargo, surge la pregunta de c u i n d o se pasivari u n objeto. Considere u n EJB de sesion c o n estado escrito de tal m o d 0 que obtiene y alberga una conexion a una base de datos; Si hay 10 conexiones disponibles bajo la licencia de la base de datos y hay 20 de estos beans de sesi6n con estado en la reserva de objetos, i q u i sucede cuando aparece el 11" cliente concurrente? Puesto que 10s beans de sesi6n sin estado

Capitulo 21
son pasivizados despuis de cada rnitodo, n o deben tener ningun problerna con albergar recursos. Sin embargo, si u n desarrollador n o ha llevado a cab0 una prograrnaci6n adecuada y ha obtenido sus recursos en el constructor del obieto, esto podria causar problernas. La raz6n por la que 10s beans de sesidn sin estado n o tienen problernas habitualrnente con la gesti6n de recursos es porque 10s desarrolladores se ajustan a un ciclo de vida conveniente para ese reciclaje. Sin embargo, estas buenas pricticas de reciclaje funcionan en todas las formas de EJB y tambikn e n servlets, piginas JSP y cualquier otra forma de objeto Java. El principio que sostiene un buen reciclaje de recursos (y, por ello, una buena reajustabilidad) consiste en adquirir y liberar recursos cuando 10s necesitarnos a lo largo de nuestro c6digo de cornponentes. Debernos adquirir un recurso justo antes de que lo necesitemos y liberarlo posteriorrnente tan pronto corno sea posible. Muchos desarrolladores tienden a evitar esta politics puesto que consideran cara la creacion y asignacidn de recursos y, por ello, lo hacen s61o una vez en el period0 de inicializacidn. La clave e s t i en utilizar recursos procedentes de reservas de recursos ya que estos estin preconstruidos y pueden ser asignado ripidarnente. Esto significa que n o tenemos que lanzarnos a la caza del recurso cuando necesiternos uno. En el nivel de ernpresa, existe una tendencia a interesarse menos por el reciclaje de recursos puesto que se presupone que el contenedor se encargari de todo. Sin embargo, el principio de liberar 10s recursos tan pronto corno sea posible sigue aplicindose.

Mas alla del sistema de pedidos de compra


El diseiio siernpre tiene lugar dentro de u n contexto. El contexto que hemos utilizado hasta el rnornento ha sido el sistema electr6nico de pedidos de cornpra para nuestra cornpaiiia ficticia. Sin ernbargo, existen muchos rnecanisrnos y patrones que resultan utiles en el diseiio de sisternas J2EE que no se requieren ni se utilizan en esta situaci6n. E n esta seccion, exarninarernos brevernente algunos de estos rnecanisrnos y patrones y 10s contextos en 10s que se aplican.

Diseno de interfaz EJB


A1 escribir u n EJB, n o es buena idea que el bean irnplernente su interfaz (de ernpresa) rernota. Esto perrnitiria que una referencia a1 rnismo bean fuera pasada de vuelta a un cliente en lugar de pasar el E J B o b j e c t asociado. Sin embargo, implernentar la interfaz rernota resulta tentador ya que le perrnite recoger cualquier firrna de mktodo incorrecta del bean antes de que lo haga el introspector del contenedor. Podernos conseguir el rnismo proposito definiendo una versidn no rernota de nuestra interfaz de ernpresa que puede ser implementada por el bean. Podemos entonces crear nuestra interfaz remota del bean heredando de la interfaz de empresa n o rernota y del E J B O b j e c t . El siguiente dIagrama muestra la jerarquia de herencia de las interfaces. Observe que 10s mitodos de nuestra interfaz de ernpresa n o remota tendrin que ser declarados para lanzar una excepcidn R e m o t e E x c e p t i o n para que funciones correctamente en la versi6n remota:

I--

lnterfaz de empresa

ja~a.ejb.~~~~bj%T_/
-

7-

A--

Consideraciones de disefio Dara a~licaciones J2EE


A diferencia del entorno C O M de Microsoft o del entorno de Componentes CORBA, Enterprise JavaBeans s610 tiene una Gnica interfaz. Esto significa que hay cuestiones relacionadas con el diseho de EJB que deben tratarse. Si el diseho del bean sugiere que debe implementar dos interfaces independientes, este requisito puede resolverse utilizando la herencia. La siguiente figura muestra una jerarquia de herencia en potencia para dos interfaces de cuentas, C u r r e n t A c c o u n t y S a v i n g s A c c o u n t . Ambas tienen ciertas operaciones administrativas en comGn per0 se diferenciarin perfectamente en el resto de operaciones. En lugar de insertar simplemente una lista de mktodos administrativos en cada interfaz y arriesgarse a que se desincronicen, cada interfaz puede heredar de otras dos interfaces; la interfaz AccountAdmin que contiene 10s mktodos comunes y una interfaz que contiene 10s mktodos especificos de la cuenta, por ejemplo, C u r r e n t o p e r a t i o n s . Esto permitiria a1 cliente reducir una r e f e r e n c i a ~ u r r e n t ~ c c o ua ntipoAccountAdmin t o C u r r e n t o p e r a t i o n s . El resto del c6digo cliente podria entonces escribirse como si fueran interfaces independientes y pudiera asegurarse la seguridad de tipo:

Observe que esto sdlo puede realizarse para las interfaces remotas de EJB. Las interfaces iniciales necesitara'n devolver diferentes tipos desde sus me'todos y, por ello, no pueden ser utilizadas de este modo.
Otra consideraci6n para interfaces EJB es la consecuencia de utilizar el descubrimiento de interfaces basado en roles. La identificaci6n del rol durante el anilisis provocari a menudo el descubrimiento de una interfaz especifica del rol que contenga mktodos especificos de ese rol. U n ejemplo de este tip0 de interfaz es la i n t e r f a z ~ c c o u n t ~ d m i presentada n, en la anterior figura, que debe limitarse a una rol administrativo. Aqui hay dos posibles rutas:

Primero, podria implementar la interfaz en una bean completamente independiente. Sin embargo, esto n o seria deseable si 10s mktodos d e ~ c c o u n t ~ d myi C n u r r e n t o p e r a t i o n s actuaran sobre 10s mismos datos subyacentes.

O La segunda ruta consiste en implementar el tip0 de jerarquia de herencia que hemos mostrado anteriormente y usar 10s atributos de seguridad en el descriptor de despliegue para aplicar la seguridad adecuada para esta interfaz virtual. Aunque esta ruta es algo improductiva, es la Gnica alternativa segura a la ausencia de multiples interfaces.
EJB 2.0 introdujo en concept0 de interfaces locales para beans de entidad que tienen relaciones dependientes y utilizan persistencia gestionada por contenedor. El EJB dependiente expone una interfaz local al EJB contenedor puesto que esti garantizado que ambas se estin ejecutando en el mismo contenedor. En este caso, se aplican las reglas habituales para interacci6n local Java (pasar por semintica de valor para referencias de objeto) y el diseho de la interfaz no es tan critico. Sin embargo, debe

Capitulo 2 1
asegurarse de que nunca seri necesario dividir estos dos EJB en un futuro utilizando persistencia gestionada por bean, antes de que la interfaz sea menos afin a la red.

Como hemos analizado anteriormente, una operation eficiente se consigue dividiendo el estado entre las gradas de presentation y de empresa. Un Objeto Valor puede actuar como representante de s61o lectura de 10s datos en el EJB asociado. Algo a tener en cuenta es q u i hacer cuando 10s datos representados cambian. Cuando 10s datos son manipulados localmente (en la misma JVM), el modelo de evento de delegaci6n funciona bien. El modelo puede lanzar cierta forma de evento de carnbio en la vista. La vista implementaria la interfaz escuchante apropiada para ese evento. El API Swing utiliza esta forma de mecanismo de evento como parte de su implementation MVC. Surge una cuesti6n cuando el modelo de datos no es local a la vista. Si la vista esti en la grada Web (o cliente) y el modelo esti en la grada EJB, no hay ningun mecanismo Java de evento distribuido preproporcionado. Sin embargo, existe suficiente estructura para crear el nuestro propio. RMI le permite configurar retrollamadas desde el servidor a1 cliente. Estas pueden ser utilizadas como la base para una version distribuida del modelo de evento de delegation. El servidor puede implementar una interfaz de registro y el cliente (o vista) puede afiadirse a si mismo como escuchante. Cuando sus datos cambian, el servidor puede informar a todos sus escuchantes del carnbio y las vistas pueden actualizarse basindose en estos nuevos datos. Si desea implementar este tipo de estructura, la Especificaci6n de Eventos Distribuidos Jini, disponible en el sitio Web de Sun, proporciona elementos para la reflexion. Otra alternativa para un sistema de eventos distribuidos en utilizar mensajes asincronos. ~ s t o pueden s ser integrados con 16gica de empresa basada en EJB, como ya hemos descrito anteriormente en el capitulo. JMS puede utilizarse para implementar varios patrones basados en mensajes o basados en eventos. La funcionalidad de inter& dependeri mucho de las fuerzas que intervengan en el sub-sistema concreto que esti intentando disefiar. Una cola de mensajes puede utilizarse para pasar mensajes desde un productor a uno o mis consumidores. El uso de mensajes punto-a-punto asegura una relacion uno-a-uno entre productor y consumidor (aunque el comportamiento en el caso que mhltiples consumidores son tan tontos como para registrarse en busca de mensajes procedentes de la misma cola es algo impreciso). Seria adecuado utilizar el sistema punto-a-punto alli donde el productor esti creando elementos de trabajo que deben ser procesados por el consumidor. Alternativamente, al tratar la distribuci6n de informacion, como las omnipresentes cuotas de existencias, puede utilizarse un modelo publicar-y-suscribir. En este caso, multiples clientes recibirin la misma informacion registrindose para recibir mensajes en un apartado especifico. Los mensajes pueden convertirse en persistentes si la aplicacion tuviera problemas si se perdieran 10s mensajes en el trayecto. De un mod0 similar, 10s consumidores pueden solicitar que un servidor reteng? una copia de cualquier mensaje publicar-y-suscribir que haya llegado para ellos cuando esten desconectados. Estos serin entregados cuando el consumidor reaparezca. Todo esto contribuye a la solidez de una aplicaci6n.

Diseno para bases de datos


Hay muchas cosas inteligentes que pueden hacerse con las bases de datos que van mis alli del alcance de este capitulo. Sin embargo, desde un punto de vista global de disetio, hay uno o dos principios que debe tener en cuenta. En primer lugar, no sea un snob de Java. Los EJB son geniales y hacen un trabajo fantistico proporcionando datos reajustables y flujo de trabajo de empresa. Sin embargo, si el rendimiento es su gran prioridad, tpor qu6 no dejar que la base de datos trabaje tanto como pueda? Es mis eficiente ejecutar

Consideraciones de disefio para aplicaciones J2EE


cddigo dentro de la base de datos que extraer 10s datos, trabajar con ellos y despuks devolverlos. Aunque integrar un procedimiento almacenado en su base de datos e invocarlo para realizar el trabajo puede n o ser tan flexible, portitil como utilizar un EJB de entidad, quizis descubra que funciona bastante mis deprisa y que puede ser m i s adecuado para las fuerzas de su aplicacion. Si debe codificar todo en Java, intente asegurarse de que tiene un servidor de base de datos que le permite ejecutar su codigo Java en el interior de la base de datos para obtener lo mejor de ambos mundos. Si esti utilizando EJB de entidad, intente evitar pelearse con la base de datos. Si esti consultando muchas tablas para construir su estado de entidad, entonces quizis tenga un serio impediment0 de correspondencia erronea entre su bean y su base de datos. Quizis quiera considerar la desregularizaci6n de su base de datos para facilitar la correspondencia con su entidad. Alternativamente, podria dividir una entidad en un conjunto de entidades dependientes que se comuniquen utilizando interfaces locales (a partir de JZEE 1.3). D e nuevo, aunque no se descubre en este capitulo, hay un buen debate sobre el uso de entidades como objetos dependientes en el patron de Entidad de Composici6n del catilogo de Patrones JZEE de Sun Java Center. En general, merece la pena dedicar bastante tiempo a su disefio de datos. El diseiio de datos tiende a evolucionar m i s despacio que el nivel medio o el nivel cliente. Si lo hace mal, puede requerir una seria reestructuracion de las otras gradas.

Lecciones aprendidas
Podriamos potencialmente haber seguido la aplicacion de sistema de pedidos de compra a travks de la entrega del pedido a1 sistema proveedor, etc. Sin embargo, esto no supondria ninguna nueva aportacion importante para el diseiio. En este punto, podemos hacer balance de las principales lecciones que hemos aprendido a partir de ejemplo y ampliarlas all: donde resulta apropiado.

Separar intereses siempre que sea posible


La separacion de intereses desemboca en una mejora de la flexibilidad y de la mantenibilidad de un sistema. Hemos visto varios ejemplos de ello en el sistema de pedidos de compra:
O

El uso de (pseudo)MCV para dividir el manejo de interfaz de usuario en presentacion (vista), comportamiento (controlador) y datos (modelo) Utilizar el patron de Ayudante de Vista en piginas JSP divide la codificaci6n Java de la presentacion de datos El cliente puede utilizar la funcionalidad de un EJB sin preocuparse por el ciclo de vida especifico de EJB y las excepciones si esti oculto detris de un Delegado de Empresa Los elementos de funcionalidad de interfaz de usuario pueden ser tratados de forma independiente construyendo una Vista de Composici6n

0 0

Este principio traspasa 10s patrones y otras decisiones de disefio encontradas en este capitulo.

Minimizar el trafico de la red


U n exceso de llamadas de red provoca atascos de rendimiento puesto que las redes repletas de datos y componentes pasan mucho tiempo esperando que esas llamadas concluyan. Cualquier reduction en el

Capitulo 21
numero de llamadas de red, en la cantidad de datos pasados y en el indice de sobregasto de red por datos pasados es util. De nuevo, este principio puede ver en la prictica en:

o El uso de Objetos Valor para evitar la programacidn basada en propiedades en la red. Los Objetos
Valor que representan un conjunto parcial de datos pueden tambien reducir 10s niveles de transferencia de datos.
0

Los Manejadores de Listas de Valores que pasan colecciones de Objetos Valor para pasar mis datos en una unica llamada. Los Manejadores de Listas de Valores permiten tambien a1 cliente detener la recuperacidn de datos cuando ya hayan sido suficientes 10s recibidos. El uso de una Fachada de Sesidn reduce el numero de llamadas procedentes del cliente para el nivel de empresa. U n Delegado de Empresa puede almacenar en cache datos y agrupar en lotes llamadas de metodo desde la perspectiva del cliente, reduciendo el trifico en la red.

Utilizar abstraccion para contribuir a la flexibilidad


Forzar al cliente para que se implique intimamente en una implementaci6n subyacente provoca un acoplamiento excesivo y una falta de flexibilidad en una aplicaci6n. Abstrayendo el servicio que debe ser provisto por el cliente, 10s detalles reales de la interacci6n pueden ocultarse y asi cambiarse siempre que sea necesario. Podemos verlo en:
0

El uso de 10s patrones de Delegado de Empresa y Localizador de Servicio para ocultar detalles subyacentes de interaccidn con EJB remotos. c o m h a multiples fuentes de datos.

0 Aplicacidn del patr6n de Objeto de Acceso a Datos para proporcionar una interfaz de cliente

U n uso comedido de la abstracci6n puede hacer que una aplicacion sea mucho mis intuitiva y mis ficil de mantener y ampliar.

Usar patrones comunes


El conjunto de patrones identificados como especificos de J2EE forman 10s inicios de un lenguaje de patr6n. En un lenguaje asi, 10s patrones se interrelacionan de formas comunes. Comprendiendo ambos patrones y cualquier combinaci6n comun de ellos, un disehador puede hacer mejor uso de 10s patrones disponibles, como vemos en:
3 Los macro patrones Servicio a1 Trabajador y Vista de Lanzador que presentan formas alternativas

comunes de utilizar un Controlador Comun con Ayudantes de Vista.


0

Todos 10s patrones especificos de J2EE presentados en este capitulo. Con el simple hecho de saber que hay patrones en estas ireas se puede ahorrar mucho tiempo y conjeturas por parte del disefiador.

Los patrones deben formar parte del equipo de herramientas de cualquier disehador o arquitecto de J2EE.

Consideraciones de disetio para aplicaciones J2EE

Reducir el acoplamiento de mecanismos asincronos


En rnuchas aplicaciones, ciertas operaciones tardarin rnucho tiempo en ser cornpletadas. Para que la aplicaci6n avance, la operaci6n debe convertirse en asincrona. Esto puede ayudar a enfrentarse a problernas de reajustabilidad y disponibilidad: El funcionarniento asincrono puede irnplernentarse de diferentes forrnas:
0 0

Los servicios especificos de rnensajeria integados en software intermediario orientado a1 rnensaje con rndtiples arquitecturas corno punto-a-punto y publicar-y-suscribir Sisternas de rnensaje ad hoc integrados en e-mail u otros sencillos transportes

O El uso de un alrnacenarniento persistente para proporcionar un punto de encuentro para el productor y el consurnidor del rnensaje
Los intercarnbios asincronos son un buen rnodo de reducir el acoplamiento entre cornponentes.

Transacciones de plan
Los sisternas s61o deben utilizar transacciones a rnedida que Sean requeridas. Las transacciones pueden ser descubiertas a partir de casos de uso y diseiiadas tal y corno sea apropiado. El tiernpo dedicado alas transacciones debe minirnizarse tanto corno sea posible para evitar la cornpetencia de recursos. N o planear 10s requisitos transaccionales puede llevar a sistemas lentos o defectuosos.

Durante rnuchos afios, he estado irnplicado en la evaluaci6n de nuevas tecnologias. A1 principio, mi tendencia era centrarrne en la tecnologia en si misrna y las diversas novedades que aportaban. C o n el paso del tiempo, ernpeck a comprender que el 90% de 10s desarrolladores del rnundo nunca utilizarian todas estas novedades. Lo que quieren es utilizar la tecnologia para resolver sus problernas de ernpresa. C o n ese prop6sit0, necesitan comprender la tecnologia y aplicarla en su propio contexto particular. La clave es asegurar que 10s desarrolladores utilizan las caracteristicas centrales de la tecnologia concreta apropiada a su contexto. La tecnologia rnisrna es de poco uso a rnenos que se aplique correctamente. Espero que haya encontrado cierto contexto familiar en este capitulo y pueda aplicar algunos de 10s principios descritos. En este capitulo, hernos analizado aspectos del diseiio J2EE, concretamente:
0

La relaci6n entre diseiio y arquitectura. base J2EE.

0 Corno el contexto provisto por un tip0 determinado de aplicaci6n puede afectar a la aplicaci6n de

n n

Una variedad de patrones especificos de J2EE que resuelven rnuchas cuestiones cornunes de diseiio surgidas a la hora de diseaar sistemas de ernpresa basados en J2EE. C6mo las diferentes tecnologias J2EE pueden aplicarse para resolver diferentes problernas de diseiio.

En el siguiente capitulo, centraremos nuestra atenci6n en 10s Servicios Web, un terna interesante y en ripida evoluci6n.

JZEE y servicios Web


Con el uso generalizado de Internet, nuestro mod0 de utilizar 10s ordenadores ha cambiado radicalmente. En sus origenes, 10s ordenadores solian ejecutar aplicaciones monoliticas y el usuario de la aplicacidn tenia que aprender desde cero todo sobre todas y cada una de las aplicaciones que queria utilizar. D e este modo, a medida que la tecnologia seguia cambiando, 10s usuarios se veian obligados a aprender nuevas aplicaciones continuamente. En lugar de que las tecnologias se adaptaran a las necesidades humanas, eramos nosotros 10s que nos veiamos obligados a adaptarnos a la tecnologia en constante cambio. C o n Internet, el foco de atencidn esti cambiando hacia software basado en servicios. Los ordenadores se utilizan para leer el correo electrdnico, obtener las cotizaciones del dia de la bolsa, pagar recibos de utilidades o simplemente para localizar el mejor restaurante chino. El software requerido para dar servicio a estos requisitos no debe ser una aplicacidn monolitica tradicional. Asimismo, el usuario de un servicio de este tipo puede acceder a1 servicio utilizando una ampliar variedad de dispositivos como PDA, tekfonos mdviles, ordenadores portitiles, etc., asi el software tradicional debe convertirse en software basado en servicios a1 que se accede ficilmente a traves de una amplia variedad de dispositivos cliente. Esto ha dado paso a una nueva raza de desarrollo de software orientado a 10s servicios. El desarrollo de software orientado a servicios es posible gracias a la utilizaci6n de tecnicas como C O M , CORBA, RMI, Jini, RPC, etc. Algunas de estas tecnicas son capaces de ofrecer servicios en la Web y otras, no. La mayoria de ellas utilizan protocolos de propiedad para la comunicacidn y sin normalizacidn. Esto dificulta que dos servicios diferentes interoperen entre si. Idealmente, estos servicios no s61o deberian interoperar entre si, sino que tambikn deberian ser capaces de integrarse y componer servicios de micro nivel en un h i c o servicio de mayores dimensiones. Sin embargo, si diferentes programadores de aplicacidn utilizan diferentes tecnologias para crear estos servicios, puede que la integracidn n o siempre sea una tarea ficil. Este concept0 consistente en crear servicios a 10s que se puede acceder a travCs de la Web ha dado lugar a un nuevo termino llamado semicio Web. En este capitulo, analizaremos este nuevo paradigma de software y, en particular, como puede ser aplicado a la plataforma J2EE. Aunque 10s servicios Web no estin especificados como parte de la especificacidn J2EE, gran parte de la tecnologia que necesitamos implementar ya esti ahi.

Capitulo 22
M i s concretamente, analizaremos:
0 Tipos de servicios Web 0 Tecnologias de servicio Web
0

Tecnologias Java para el desarrollo de servicios Web

0 Servicios Web inteligentes

Pero, antes de seguir adelante, debemos entender con exactitud lo que queremos decir con el tCrmino servicio Web.

iQue son 10s servicios Web?


U n servicio Web puede definirse corno:

U n componente de aplicaci6n accesible a travks de protocolos Web estindar.

U n servicio Web es como una unidad de lbgica de aplicacibn. Proporciona servicios y datos a clientes remotos y otras aplicaciones. Los clientes y las aplicaciones remotas acceden a servicios Web a travCs de protocolos de Internet omnipresentes. Utilizan XML para el transporte de datos y S O A P (Simple Object Access Protocol) para hacer uso d,e servicios. Debido a1 uso de XML y SOAP, el acceso a1 servicio es independiente de la implementac16n. Asi, un servicio Web es como una arquitectura de componentes para la Web. Igual que sucede con un modelo de desarrollo de componentes, un servicio Web debe tener 1as dos siguientes caracteristicas:
0

Registro con un servicio de b6squeda

0 Una interfaz p6blica para que el cliente invoque el servicio

Cada servicio Web debe registrarse en un repositorio central de mod0 que 10s clientes puedan buscar en el registro el servicio deseado. Una vez localizado el servicio, el cliente obtiene una referencia a1 servicio. El cliente utiliza entonces el servicio invocando varios metodos implementados en el servicio con la ayuda de una interfaz pliblica publicada. Asi, cada servicio debe publicar su interfaz para el uso de 10s clientes. Ademis de las anteriores caracteristicas esenciales, un servicio Web debe tambiCn poseer las siguientes caracteristicas:
0 Debe utilizar protocolos Web estindar para comunicaci6n 0 Debe ser accesible desde la Web 0 Debe ajustarse a1 acoplamiento dCbil entre sistemas distribuidos no acoplados de mod0 que 10s sistemas ejecutados en diferentes plataformas y basados en diferentes tecnologias puedan cooperar entre si para formar un sistema distribuido

Los servicios Web reciben informacibn procedente de clientes como mensajes, que contienen instrucciones sobre lo que desea el cliente, similares a las llamadas de mCtodos con parimetros. Estos mensajes, que tambikn son entregados por un servicio Web a1 cliente cuando concluye el servicio, son codificados utilizando XML y las interfaces pliblicas tambien son descritas en XML. XML proporciona transporte de datos neutral con referencia a la plataforma. De este modo, 10s servicios Web capacitados para XML pueden, tebricamente, interoperar con otros servicios Web capacitados para XML siempre que

J2EE y servicios Web


dos servicios estkn de acuerdo en un protocolo cornfin para la cornunicacibn. Los protocolos utilizados por servicios Web para la cornunicaci6n estin siendo norrnalizados y 10s analizarernos en las siguientes secciones.

Servicios inteligentes
En estos dias, la rnera introducci6n de servicios Web n o es suficiente. Los usuarios de un servicio Web quieren que el servicio sea lo suficienternente inteligente para cornprender el contexto en el que se invoca y actuar consecuenternente. Por ejernplo, si esti utilizando un servicio Web para buscar un restaurante, el servicio debe ser lo suficienternente inteligente para buscar sus preferencias personales, su historial de 10s ultirnos dias con relaci6n a 10s lugares donde ha cornido y ofrecer sugerencias apropiadas. Alternativarnente, suponga que esti utilizando un servicio Web para hace una reserva de viaje. La politica de su ernpresa quizis le perrnita viajar en clase preferente, aunque quizis viajaria en a u t o b k en sus viajes personales. El servicio deberia detectar autorniticarnente el contexto y ofrecer consecuenternente las sugerencias para sus reservas de viajes. Estos servicios se llarnan servicios inteligentes y pueden proporcionar contenidos utilizando tecnicas de personalizaci6n. Los servicios inteligentes serin tratados con rnis detenirniento rnis adelante, en este rnisrno capitulo. Despuks de haber visto en que consisten 10s servicios Web, analizarernos ahora las tecnologias requeridas para el desarrollo de estos servicios Web.

Tecnologias de servicios Web


Hay una aplica variedad de tecnologias que apoyan 10s servicios Web. Las siguientes tecnologias estin disponibles para la creaci6n de servicios Web. Son tecnologias neutrales en su relaci6n con el vendedor. Exarninarernos brevernente estas tecnologias antes de continuar con 10s que Java nos ofrece en el carnpo de 10s servicios Web:
0 SOAP 0 Mensajes SOAP con anexos 0 WSDL 0 UDDI 0 ebXML

S O A P (Simple Object Access Protocol, vkase http : / /www. w3 .org/TR/SOAP/ para rnis detalles) es un protocolo de base XML ligero y sencillo. SOAP perrnite el intercarnbio de inforrnaci6n estructurada y tecleada sobre la Web, describiendo un forrnato de rnensaje para la cornunicaci6n equipo-a-equipo. SOAP perrnite la creacidn de servicios Web basados en una infraestructura abierta. SOAP consiste en tres partes:
0 Sobre S O A P Define el contenido de un rnensaje, quikn es el receptor del rnensaje y si el rnensaje es opcional u obligatorio.

Capitulo 22
0 Reglas de codificaci6n S O A P Define un conjunto de reglas para intercarnbiar instancias de tipos de datos definidos por la aplicaci6n.
O

Representaci6n R P C S O A P Define una convencidn para representar llarnadas de procedimiento rernoto y respuestas.

SOAP puede utilizarse en cornbinaci6n con una variedad de protocolos y forrnatos de Internet existentes incluido HTTP, SMTP y MIME, y puede ajustarse a una arnplia garna de aplicaciones desde sisternas de rnensajeria a W C . Sin embargo, en el rnornento de la publicaci6n de este libro, s610 se ajusta a la asociaci6n HTTP. ~ s t es e un tipico rnensaje SOAP:
<IVORY:Envelope xmlns:IVORY="http://schemas.xmlsoap.org/soap/er~velope/" IVORY :encodingStyle="http: //schemas. xmlsoap. org/soap/er~codir~g/">

Corno podernos ver en este ejernplo, un rnensaje SOAP esti codificado utilizando XML. SOAP define dos espacios de nornbre estindar, uno para el sobre (http://schemas.xmlsoap.org/soap/enevelope/) y el otro para las reglas de codificaci6n (http://schemas.xmlsoap.org/soap/encoding/). U n rnensaje SOAP no debe contener D T D (Definicibn de Tipo de Docurnento) y no debe contener ninguna instrucci6n de procesarniento. El anterior rnensaje SOAP define un metodo llamado GetLastTradePrice que torna un sirnbolo bursitil corno parirnetro. El consurnidor del servicio Web crea un rnensaje SOAP corno el anterior, lo integra en una solicitud POST H T T P y la envia para que sea procesada por el servicio Web:
POST /StockQuote HTTP/1.1 Host: www.stockquoteserver.com Content-Type: text/xml; charset="utf-8" Content-Length: nnnn SOAPAction: "Sorne-URI"

...

SOAP Message

El servicio Web procesa el rnensaje, ejecuta la operaci6n solicitada y devuelve el resultado a1 cliente en forrna de otro rnensaje SOAP. El rnensaje contiene ahora el i n d i ~ e bursitil solicitado. U n tipico rnensaje SOAP de retorno puede ser ask

El rnensaje puede ser devuelto a1 cliente corno una respuesta HTTP y contendri la cabecera HTTP adecuada en la parte superior del rnensaje. Corno veri, en este rnensaje estarnos diciendo a1 cliente que la

J2EE v servicios Web


respuesta a su l l a r n a d a ~ e t ~ a s t ~ r a d e ~ es ri 3c 4e . 5 ; si el cliente hubiera realizado solicitudes a rnis rnktodos, la respuesta contendria rnis valores de retorno.

lnteroperabilidad
El orincioal obietivo en el diserio de SOAP fue oerrnitir una ficil creaci6n de servicios Web distribuidos interoperables (proporcionando ficil acceso a objetos). Puesto que 10s servicios pueden ser descritos en XML, es rnucho rnis ficil describir servicios en arquitecturas RMI, CORBA o EJB. Algunos detalles de especificaciones SOAP estin abiertos a la interpretaci6n; sin embargo, la irnplernentaci6n difiere entre vendedores. Asi, 10s rnensaies creados Dor diferentes aolicaciones difieren en su nivel de adaptaci6n teniendo corno resultado aplicaciones no interoperables. Observe que un docurnento XML vilido puede no ser necesariarnente un rnensaje SOAP vilido y, sirnilarrnente, un rnensaje SOAP vilido puede no ser un rnensaje SOAP vilido. Lo que esto significa es que un rnensaje SOAP, aunque es un rnensaje XML vilido, puede que no siga estrictarnente la especificaci6n SOAP. Para probar el grado de conformidad, pueden utilizarse herrarnientas terceras. Una herramienta de este tip0 llarnada SOAP Message Validator esti desarrollador por Microsoft y esti disponibleenhttp: //www. s o a p t o o l k i t .com/soapvalidator/.Utilizandolaherrarnientade convalidaci6n, puede cornprobar si cualquier c6digo SOAP se corresponde con la especificaci6n SOAP 1.1

lmplementaciones
La tecnologia SOAP ha sido desarrollada por DevelopMentor, IBM, Lotus, Microsoft y Userland. Mis de 50 vendedores han irnplernentado SOAP hoy en dia. Las irnplernentaciones rnis populares son la de Apache, que es una irnplernentaci6n de base Java de fuente abierta, y la de Microsoft, dentro de su plataforrna .NET. Las dos irnplernentaciones tienen algunas discrepancias que hacen que las aplicaciones desarrolladas utilizando las dos tecnologias no Sean interoperables. La especificacidn SOAP ha sido presentada a W3C (World Wide Web Consortium), que esti trabajando en estos rnornentos en nuevas especificaciones llarnadas XMLP (Protocolo XML) que esti basado en la versi6n 1.1 de SOAP.

Mensajes SOAP con anexos (SwA)


Quizis necesite enviar un rnensaje SOAP con un anexo consistente en otro docurnento o en una irnagen, etc. En Internet, 10s forrnatos de datos G I F v son tratados corno estindares de facto para , TPGE " trasrnisi6n de irnigenes. En general, 10s anexos pueden estar en forrnato de texto o binario. La segunda iteraci6n de la especificaci6n SOAP (SOAP 1.1) perrnitia que 10s anexos fueran cornbinados con un rnensaje SOAP utilizando una estructura MIME rnultiparte. Esta estructura rnultiparte se denornina Paquete de Mensajes SOAP. Esta nueva especificaci6n ha sido desarrollada por H P y Microsoft y ha sido presentada a1 W3C. Esta es una rnuestra de un rnensaje SOAP que contiene un anexo (myimmage .t i f f ) : MIME-Version: 1 . 0 C o n t e n t - T y p e : M u l t i p a r t / R e l a t e d ; boundary=MIME b o u n d a r y ; s t a r t = " < m y i m a g e d o c . x m l @ m y s i t ecorn>" . type=text/xml;

Content-Description: This i's the optional message description. -MIME boundary Content-Type: text/xml; charset=UTF-8 Content-Transfer-Encoding: 8bit Content-ID: < r n y i m a g e d o c . x m l @ r n y s i t e . c o r n >

Capitulo 22

-MIME boundary Content-Type: image/tiff Content-Transfer-Encoding: binary Content-ID: <rnyimage.tiff@mysite.com>

. . .binary TIFF image.. -MIME-boundary-

El Lenguaje de Descripci6n de Servicios Web (WSDL) es un formato XML para describir una interfaz de servicio Web. Un archivo WSDL define el conjunto de operaciones permitidas en el servidor y el formato que el cliente debe seguir al solicitar el servicio. El archivo WSDL actGa como un contrato entre el cliente y el servicio para una comunicaci6n efectiva entre las dos partes. El cliente tiene que solicitar el servicio enviando una solicitud bien estructurada y que se ajuste a SOAP. Como ejemplo, si estuviCramos creando un servicio Web que ofreciera las Gltimas cotizaciones de la bolsa, seria necesario que creiramos un archivo WSDL en el servidor que describiera el servicio. El cliente obtendria primer0 una copia de este archivo, comprenderia el contrato, crearia una solicitud Web basada en el contrato y lanzaria la solicitud a1 servidor utilizando un Puesto HTTP. El servidor valida la solicitud y, si es vdida, la ejecuta. El resultado, que es el Gltimo indice bursitil para el simbolo requerido, es devuelto entonces a1 cliente como una respuesta SOAP.

Documento WSDL
Un documento WSDL es un documento XML que consiste en un conjunto de definiciones. Primero, declaramos 10s espacios de nombre requeridos por la definici6n del esquema:

El elemento raiz es d e f i n i t i o n s , como mostramos aqui:

El atributo name es opcional y puede servir como una forma 1igera de documentaci6n. nmtoken representa testigos de nombre que son cadenas cualificadas similares a CDATA, per0 el uso de caracteres esti limitado a letras, digitos, subrayado, dos puntos, punto y barras. Opcionalmente, un t a r g e t N a m e s p a c e puede especificarse proporcionando u n u r i . La etiquetaimport puede utilizarse para asociar un espacio de nombre con una localizacion del documento. Asi, 1as definiciones pueden contener el espacio de nombre de destino, que se asocia entonces a la localizacidn del documento en una

J2EE y servicios Web


instrucci6n i m p o r t posterior. El siguiente segrnento de c6digo muestra cdrno el espacio de nombre declarado se asocia mis tarde a la localizaci6n del docurnento especificada en la instrucci6n i m p o r t :

Finalrnente, el elemento opcionalwsdl : d o c u m e n t a t i o n es utilizado para declarar docurnentaci6n legible. El elernento puede contener cualquier texto arbitrario. Dentro de las definiciones, aiiadiri otros elernentos. Existen seis elementos principales en la estructura del docurnento que describen el servicio. Son 10s que enurnerarnos a continuaci6n:

0 types 0 message

binding

0 port 0 service

Elelemento

types

El elernento t y p e s proporciona definiciones para tipos de datos utilizados para describir c6rno 10s rnensajes intercarnbiarin datos. La sintaxis para el elernento t y p e s es la siguiente:
<wsdl :types> ? <wsdl:documentation . . . . />? <xsd: schema . . . . />* <- extensibility element -> </wsdl : types>

La etiquetawsdl : d o c u m e n t a t i o n es opcional como en el caso d e d e f i n i t i o n s . El sisterna de tipo x s d puede utilizarse para definir tipos en un rnensaje. Como quizis n o sea posible tener una gramitica de sisterna de un h i c o tip0 para describir todos 10s tipos abstractos, WSDL permite que 10s sisternas tip0 Sean aiiadidos a travks del elernento de extensibilidad. U n tipico ejernplo de una secci6n < t y p e s > se muestra a continuaci6n. Aqui se define un elernento llarnado S t o c k Q u o t e S e r v i c e . El semicio requeriri un parirnetro de entrada de tipo string, con el nombreticker~yrnbol:

Capitulo 22

U n elernento m e s s a g e representa una definici6n abstracta de 10s datos transrnitidos. La sintaxis para el elernento m e s s a g e es la siguiente:

El atributo mes s a g e name se utiliza para definir un nornbre 6nico para el rnensaje dentro del alcance el docurnento. Corno en casos anteriores, w s d l : d o c u m e n t a t i o n es opcional y puede utilizarse para declarar docurnentaci6n legible. El rnensaje consiste en una o rnis partes 16gicas. p a r t describe el contenido abstracto 16gico de un rnensaje. Cada p a r t e consiste en un nornbre y en atributos opcionales e l e m e n t y t y p e . El elernento y su tipo pueden ser declarados con anterioridad en la secci6n t y p e s .

A continuaci6n se rnuestra un t i p i c o m e s s a g e . El nombre del rnensaje es s t o c k Q u o t e S e r v i c e .


S t o c k Q u o t e s debe definirse en el espacio de nornbre en la secci6ndef i n i t i o n s :

El elernento p o r t T y p e define el conjunto de operaciones abstractas. Una operaci6n consiste en mensajes de entrada y de salida. Corno se rnuestra en la siguiente sintaxis, la etiqueta o p e r a t i o n define el nornbre de la operacibn, input define la entrada para la operaci6n y output define el forrnato de salida para el resultado. El elernento f a u l t se utiliza para describir 10s contenidos del elernento de 10s detalles de fallos SOAP. El elernento de detalles de fallos especifica el forrnato abstracto del rnensaje para 10s rnensajes de error que pueden producirse como resultado de la operaci6n:
<wsdl:portType name="nmtokenfl>* <wsdl :documentation . . . . />? <wsdl:operation name="nmtoken">* <wsdl :documentation . . . . /> ? <wsdl : input name="nmtoken" ? message=" qname">? <wsdl :documentation . . . . /> ? </wsdl :input> <wsdl : output name="nmtoken" ? message="qnameU>? <wsdl :documentation . . . . /> ? </wsdl:output> <wsdl:fault name="nmtokenl' message="qname"> * <wsdl :documentation . . . . /> ? </wsdl : fault> </wsdl:operation> </wsdl :portType>

El elernento b i n d i n g define el protocolo que debe ser utilizado y especifica el forrnato de 10s datos para las operaciones y rnensajes definidos por un deterrninado p o r t T y p e . La sintaxis cornpleta para b i n d i n g es la siguiente:

J2EE v servicios Web


< w s d l : d o c u m e n t a t i o n . . . . />? <-- e x t e n s i b i l i t y e l e m e n t --> < w s d l : o p e r a t i o n name="nmtokenl'>* <wsdl: d o c u m e n t a t i o n . . . . /> ? <-- e x t e n s i b i l i t y e l e m e n t --> * <wsdl : i n p u t > ? <wsdl:documentation . . . . /> ? <-- e x t e n s i b i l i t y e l e m e n t --> </wsdl:input> <wsdl: o u t p u t > ? <wsdl:documentation . . . . /> ? <-- e x t e n s i b i l i t y e l e m e n t --> * </wsdl : o u t p u t > <wsdl : f a u l t name="nmtoken"> <wsdl:documentation . . . . /> ? <-- e x t e n s i b i l i t y e l e m e n t --> </wsdl: f a u l t > </wsdl:operation> </wsdl:binding> Las operaciones del archivo WSDL pueden estar orientadas el "documento" u orientadas a una "llamada de procedimiento remoto (RPC)". El atributo de estilo del elemento<soap :b i n d i n g > define el tipo de operaci6n. Si la operaci6n esta orientada a1 documento, 10s mensajes de entrada y de salida consistiran en documentos XML. Por ejemplo, puede enviar un pedido para una compra de acciones a1 servicio Web S t o c k Q u o t e como un documento XML. A cambio, recibira un documento XML que confirme la ejecucion de la solicitud en la bolsa. Estos documentos XML pueden ser procesados utilizando cualquier analizador XML disponible. Si la operacion esta orientada a RPC, entonces el mensaje de entrada contiene 10s parametros de entrada de la operaci6n y el mensaje de salida contiene 10s resultados de la operacion. El servicio Web puede definir una operacion orientada a R P C como la multiplicaci6n de dos matrices. En este caso, 10s parimetros de entrada serin las dos matrices y la salida consistiri en la matriz resultante devuelta por el servidor.

El elemento p o r t
U n elemento p o r t define un extremo individual especificando una bnica direcci6n para una asociaci6n: < w s d l : p o r t name="nmtokenU b i n d i n g = " q n a m e f l > * <-- e x t e n s i b i l i t y e l e m e n t (1) --> </wsdl : p o r t > El atributo name define un nombre exclusive para el puerto dentro del documento WSDL actba. El atributo b i n d i n g hace referencia a la asociaci6n y el elemento de extensibilidad es utilizado para especificar la informaci6n de la direccion para el puerto.

El elemenfo service
El elemento s e r v i c e agrega un conjunto de puertos relacionados. C a d a p u e r t o especifica una direction para una asociaci6n: <wsdl : service n a m e = " n m t o k e n n > * < w s d l : d o c u m e n t a t i o n . . . . />? < w s d l : p o r t name="nmtokenM b i n d i n g = " q n a m e U > * <wsdl:documentation . . . . /> ? <-- e x t e n s i b i l i t y e l e m e n t --> </wsdl : p o r t > <-- e x t e n s i b i l i t y e l e m e n t --> </wsdl:service>

Capitulo 22

Despuks de haber creado servicios Web, necesitari publicarlos de mod0 que 10s compradores y socios de empresa puedan localizar 10s servicios que ofrece. Asi, lo que necesita es un registro comdn donde registrar su servicio Web para que 10s clientes lo encuentren. C o n este prop6sit0, se form6 un consorcio industrial encabezado por Accenture, Commerce One, Compaq, Edifecs, Fujitsu, H P , 12, IBM, Intel, Microsoft, Oracle, SAP, Sun Microsystems y Verisign. Fundaron el proyecto de Descripci6n, Descubrimiento e Integraci6n Universal, Universal Description, Discovery, and Integration (UDDI). H o y en dia, mis de 250 cornpahias se han sumado a1 proyecto UDDI. La principal tarea del proyecto es desarrollar especificaciones para un registro de empresas de base r resto descubrir 10s servicios Web Web. El registro ~ o d e describir r un servicio Web v ~ e r m i t i a1 " registrados. En la actualidad, hay una implementaci6n de muestra, junto con otros recursos, disponible en http://www.udi.org.
2 .

El registro U D D I permite a cualquier organizacidn publicar informaci6n sobre sus servicios Web. El sistema define una norma para que las empresas compartan informaci611, describan sus servicios y sus negocios y decidan quC informaci6n se hace pdblica y quC informaci6n se mantiene en privado. La especificacion tambiin define una interfaz que un programador interactde con el registro. La interfaz esti basada en XML y SOAP y utiliza HTTP para interactuar con el registro. El registro alberga informaci6n sobre una empresa como el nombre de la compahia, contactos, etc., y tambiCn alberga la informaci6n descriptiva y tCcnica del servicio Web proporcionado por la empresa. Esta informaci6n consiste en el URL para el servicio Web y punteros a contratos de servicios, y las especificaciones tkcnicas del servicio. El registro U D D I proporciona funciones de bkqueda para permitirle buscar segmentos de industria especificos y/o localizaciones geogrificas. La bdsqueda tambien le permite localizar socios que tengan software compatible de mod0 que pueda compartir documentos creados utilizando este software.

C o m o hemos mencionado anteriormente, la implementaci6n de la especificacibn actual esti disponible en el sitio http://www.uddi.org/. Es un registro global, pdblico llamado registro de empresa UDDI. Los particulares pueden establecer registros U D D I privados. Las implementaciones para crear registros privados estin disponibles en IBM, Idoox, jUDDIorg y Mind Electric. Microsoft ha desarrollado un SDK U D D I que permite a un programador Visual Basic escribir un c6digo de programa para interactuar con el registro UDDI. El SDK U D D I puede descargarse desde el sitio de MSDN (http://msdn.microsoft.com). El uso de este SDK simplifica en gran medida la interacci6n con el registro y protege a1 programador de detalles de nivel local de XML SOAP.

Como las especificaciones anteriores, ebXML (electronic business XML) es un conjunto de especificaciones que permiten a las empresas colaborar ( h t t p : / ~ . e b x m l . o r g / ) .ebXML es un mercado electronico global donde las empresas pueden encontrarse y realizar transacciones con la ayuda de mensajes basados en XML. Las empresas pueden estar localizadas geogrificamente en cualquier lugar del mundo y ser de cualquier dimensi6n para poder participar en el mercado global. La iniciativa ebXML esti financiada coniuntamente por el Centro de las Naciones Unidas para la Ayuda a1 Comercio y las Empresas Electr6nicas (UN/CEFACT, http:Nunece.org/cefac~y la Organizaci6n para el Avance de las Normas de Informacion Estructurada (OASIS, http://www.oasis-open.org/). La afiliaci6n actual a este

J2EE v servicios Web


registro incluye la representation de mis de 200 ernpresas, gobiernos, instituciones, organisrnos estindar y particulares. La estructura define especificaciones para el uso cornpartido de sewicios de ernpresa de base Web. Incluye e~~ecificaciones para un sewicio de rnensajes, acuerdos de socios en colaboracion, cornponentes nucleares, una rnetodologia de proceso de ernpresa, un registro y un repositario. ebXML define un registro y un repositorio en el que las ernpresas pueden registrarse proporcionando su inforrnacidn de contacto, direccibn, etc. a traves de un forrnato de docurnento estindar. Esta inforrnaci6n se conoce como cornponente nuclear. Una vez que la empresa presenta componentes nucleares, puede despues proveer informaci6n sobre sus productos y sewicios. Despuks de que una ernpresa se ha registrado en el registro ebXML, otros socios (por ejemplo, un consumidor de sewicios) pueden buscar en el registro para localizar tales empresas. Una vez se ha localizado un socio de empresa (por ejemplo, un proveedor de sewicios), se descargan 10s cornponentes nucleares de la ernpresa localizada. El consumidor puede entonces descargar las especificaciones tkcnicas para el sewicio. Una vez que el consurnidor esti satisfecho con el hecho de que el sewicio proveedor pueda curnplir sus requisitos, negocia un contrato con el proveedor. Estos acuerdos de socios en colaboraci6n estin definidos en ebXML. Cuando arnbas partes estin de acuerdo en 10s tkrrninos del contrato, firrnan 10s acuerdos y realizan una transaccion de ernpresa cooperativa intercambiando sus docurnentos privados. ebXML ofrece un mercado y define diversos docurnentos de base XML para que las ernpresas de adhieran y realicen transacciones en este rnercado.

Tecnologias JZEE para servicios Web


Despues de haber visto varias tecnologias para crear sewicios Web, analizaremos ahora lo que tiene que ofrecer JZEE. La plataforma JZEE proporciona un paquete JAX (API Java para XML, http:// java.sun.co~xrnVjaxpack.htrnl) que contiene varios paquetes mis para tecnologias XML que colaboran en la creaci6n de un sewicio Web. JAX proporcionar API para SAX, DOM, XSLT, SOAP, UDDI, WSDL y ebXML, poniendo haciendo todas estas tecnologias disponibles a traves de un lenguaje de programacion corndn (Java), perrnitiendo, asi, una ficil interoperabilidad entre aplicaciones que utilicen v XML neutral en relacion con el estas tecnoloeias. Siendo lava neutral en relacion a la ~lataforma vendedor, estos API ayudarin a las empresas a crear aplicaciones y sewicios Web que sean neutrales respecto de la plataforrna y del vendedor, perrnitiendo un ficil uso compartido de docurnentos y sewicios.
G .

El paquete J A X todavia esta' emergiendo y no todos 10s API esta'n ya en la entrega final. De hecho, s d o algunos de estos API tienen una implementaci6n de referencia disponible y algunos 5610 a travt% del primer programa de acceso de Sun. Sun ha prometido frecuentes actualizaciones de J A X para garantizar que la tiltima tecnologia X M L Java se encuentra a disposicidn de 10s desarrolladores de sewicios Web.
El paquete JAX incluye las siguientes tecnologias:
0 JAXP- API Java para Procesamiento XML 0 JAXB- Arquitectura Java para Asociacion XML
0 JAXM- API Java para Mensajeria XML

0 JAX-RPC- API Java para RPC basado en XML


O JAXR- API Java para Registros XML

Capitulo 22
Ahora analizaremos brevemente cada una de estas tecnologias.

Para mris informacio'n sobre cualquiera de estos API, consulte Professional Java X M L ( I S B N 1861004-01-X) o Java XML Programmer's Reference ( I S B N 1-861005-20-2).

El API JAXP apoya el procesamiento de documentos XML utilizando SAX (Simple API para procesamiento XML) o D O M (Document Object Model). Tambien sirve como API para transformaciones XML (XSLT, Extensible Stylesheet Language Transformations). El API proporciona una mayor abstracci6n para procesadores XML y permite a1 desarrollador acoplar cualquier procesador XML dependiendo de las necesidades de tiempo. Algunos de 10s procesadores XML pueden proporcionar alto rendimiento con el coste de 10s recursos consumidos mientras que otros procesadores pueden conservar el uso de recursos. El desarrollador tiene la flexibilidad de cambiar entre procesadores. Esta abstraccion de alto nivel permite a 10s desarrolladores ajustar a XML sus aplicaciones Java y convertirlas en aplicaciones de base Web. El paquete JAXP ofrece una implementaci6n de referencia que incluye un analizador para SAX y para D O M y un sistema de transformaci6n que apoya XSLT. La ultima entrega (versi6n 1.1) se ajusta a SAX 2.0 y a D O M nivel2. El API 1.1 tambitn incluye una estructura XSLT basada en un API de Transformacibn para XML (TrAX).

Utilizando JAXP, puede acoplar el analizador XML que elija en su c6digo de programa. Los analizadores resultan <tiles si desea analizar el documento complete; sin embargo, hay situaciones en las que puede necesitar acceder a datos parciales de un documento XML. Por ejemplo, si su programa quiere leer el valor de la cantidad de compra desde un documento de pedido de base XML, es mucho mis ficil utilizar un mCtodo como g e t Q u a n ti t y ( ) en lugar de analizar el documento completo utilizando analizadores SAX o DOM. De un mod0 similar, a1 presentar el pedido, para establecer la cantidad, seria mis eficiente utilizar un metodo como s e t Q u a n ti t y ( ) . Asi, un desarrollador de aplicacion necesita una forma sencilla de acceder y manipular 10s datos contenidos en una documento XML; algo tan sencillo como 10s metodos get yset. La tecnica de asociaci6n de datos XML esti basada en esta idea. La tecnica requiere el uso de Esquemas XML. Analizaremos brevemente 10s Esquemas XML antes de proceder a la explicaci6n de la tecnica de asociaci6n de datos XML.

Esquema XML
La forma mis comun de describir la estructura de un documento XML es creando una Definition de Tipo de Documento (DTD). El Esquema XML es un nuevo estindar para describir la estructura del documento y el tip0 de datos para su contenido. U n fragment0 de un tipico Esquema XML:

J2EE y servicios Web


>
<EiementType narne="Catalog"> < a t t r i b u t e name="bookNarne" t y p e = " s t r i n g " / > < a t t r i b u t e narne="editionM t y p e - " f l o a t " /> </ElernentType>

El Esquema XML no solo describe la estructura del documento XML, sino que tambien permite comprobar los datos del elemento. De este modo, es ficil escribir un programa Java que valide el documento XML frente a su esquema para la estructura y el tipo de cada elemento. Por ejemplo, es muy sencillo cornprobar si un determinado elemento contiene un valor numkrico o no numkrico frente a su definition en el esquema. El programa puede capturar ficilmente esos errores y lanzar excepciones si 10s tipos de datos no se corresponden con 10s definidos en el esquema. Resumiendo, 10s Esquemas XML ofrecen las siguientes ventajas:
0

Definen la estructura de un documento XML como D T D

u Permiten la comprobacion del tip0 en 10s datos del elemento


O Permiten una ficil validacidn pata la estructura y el tipo de datos

D e este modo, el uso de Esquemas XML se ha preferido a1 uso de D T D a la hora de disefiar la asociacion de datos XML.

Asociaci6n de datos XML


La tecnica de asociacih de datos XML es el resultado de un codigo de proyecto Sun 1lamadoAdelard y conocido como JAXB. El proyecto tenia 10s siguientes objetivos a la hora de disefiar estos API: Facilidad de uso: los desarrolladores no necesitan ser expertos en XML Personalizable: el Esquema estindar XML todavia esti evolucionando por lo que el nuevo API debe reflejar 10s cambios efectuados en las especificaciones del esquema
0

Rapidez: debe ser capaz de manejar largo documento de forma eficiente Reducido: el c6digo generado debe ser lo suficientemente reducido para caber en pequefios dispositivos debe ser compatible con 10s D T D ya que estos todavia son de uso generalizado

O Compatibilidad con DTD: aunque el EsquemaXML se utiliza en este proyecto, la futura entrega

La tkcnica de asociaci6n de datos asocia el Esquema XML con clases Java, que pueden ser utilizadas por su codigo de programa.
Cada elemento del esquema puede asociarse a una exclusiva clase Java que contenga varios metodos g e t / s e t para operar en 10s atributos del elemento. Las clases generadas deben cumplir 10s siguientes objetivos:
0 Estar basadas en convenciones estindar de API 0 Representar conceptualmente el esquema 0 N o precisar anilisis, ni SAX ni D O M
O Permitir la subclasificacion para personalizacion
0 Tener objetos serializables

o Permitir la validacion de instancias de documentos sin lectura (marshaling)

Capitulo 22
Para asociar el Esquema XML a clases Java, se ha desarrollado un compilador de esquema en la implementaci6n de referencia. El compilador convierte el esquema dado en un conjunto de clases Java que pueden ser utilizadas directamente en su c6digo de

programs:

Equeme 1

.A'

, Clase . Java-

-_-

Clase
I

>

' r
Clase
" ,~ava~,'

A--.

Java;

Clase I , Clase Java

El c6digo generado incluye validaci6n de estructura y validaci6n de contenido de datos tal y como se define en el esquema. Esto libera a1 programador de implementar reglas de validaci6n en el c6digo del programa. Las clases Java generadas son cornpiladas en un c6digo byte Java y tienen asi mayor rendimiento en cornparaci6n con cualquier validaci6n dinimica implementada en programas basados en SAX o en DOM. Asimismo, las clases Java pueden volver a ser creadas rdpida y automdticamente utilizando el compilador del esquema. Esto reduce en gran medida el mantenimiento del c6digo. Puesto que el compilador genera automiticamente el c6digo Java requerido junto con las validaciones especificadas, esto reduce ampliarnente el tiempo desarrollo de la apkaci6n. Una aplicaci6n que utilice la ticnica de asociaci6n de datos puede ejecutarse tan ripido como una aplicaci6n basada en SAX. A1 mismo tiempo, tambiin aporta 10s beneficios de una estructura en memoria del documento XML similar a1 analizador de base DOM. Resumiendo, la tecnica de asociaci6n de datos utiliza un compilador de Esquerna XML para asociar el esquema a un conjunto de clases Java que pueden ser utilizadas directarnente por una apkaci6n Java. Estas clases Java proporcionan validaci6n de estructura y de contenido y reducen en gran medida el tiernpo de desarrollo y el coste de mantenimiento. Las clases generadas tambikn proporcionan un mecanismo para la conversi6n entre documentos XML y objetos Java. El uso de la ttcnica de asociaci6n de datos puede simplificar considerablemente el desarrollo de servicios Web que requieren XML para el intercambio de datos.

El API Java para Mensajes XML (JAXM) perrnite a las aplicaciones enviar y recibir mensajcs XML orientados al docuniento utilizando un API Java. Se ajusta a la especificaci6n SOAP 1.1 y a SOAP con anexos. El modelo conceptual que muestra la relaci6n entre JAXM y otros elementos en una situaci6n de envio de mensajes B2B es el siguiente:

J2EE y servicios Web

El servidor de la Oreanizacibn B imdementa el API JAXM. El proveedor JAXM es responsable de la . , transmision y recepci6n de mensajes SOAP. El cliente utiliza JAXM para comunicar con el servidor. El mensaje siempre estd centrado en el documento y puede ser entregado sincrdnicamente o asincronicamente. En caso de entrega sincrona de mensaje, el cliente espera hasta que el mensaje ha sido procesado por completo por el servidor y esperari al acuse de recibo del servidor antes de proceder. En caso de entrega asincrona, el cliente no espera al acuse de recibo del servidor y continuari con su trabajo.

Los proveedores JAXM deben ajustarse a HTTP; adicionalmente, plreden ajustarse a otros protocolor como FTP y SMTP en slrs implementaciones.
El modelo de empaquetado SOAP utilizado por JAXM esti representado en el siguiente diagrams:

Capitulo 22

- SOAP I . l + S o b r e de Anexos MIME

--

Sobre
I
-

.-

..

SOAP-SOBRE:

i
SOAP-SOBRE:

i par 6 Anexo

Anexo SOAP (XML o no-XML)

JAXM define una interfaz estindar para producir y consumir mensajes con o sin anexos. JAXM utiliza JavaBeans Activation Framework (JAF) para manejar 10s anexos basados en el tipo MIME. Ademis de mensajes SOAP y SOAP con anexos, la especificaci6n JAXM se ajusta a 10s protocolos de mensajeria basidos en estindares de nivel superior. Estos protocolos de nivel superior proporcionan generalmente funcionalidad adicional mis alli de la proporcionada por la mensajeria basada en SOAP. U n ejernplo de este estindar de nivel superior es ebXML. Esta caracteristica se denomina perfiles de mensajeria y permite a 10s desarrolladores tener una funcidn de mensajeria XML conectable en sus programas de aplicaci6n. Esto tiene como resultado aplicaciones basadas en mensajes reajustables, sdlidas y seguras.

Este API proporciona un API independiente del transporte para protocolos de RPC (Ilamadas de procedimiento remoto) de base XML estindar. Este API todavia esti siendo desarrollado por el Proceso de Comunidad Java (JCP) y, en el momento de publicacidn de este libro, no existe ninguna

J2EE y servicios Web


implementacidn de referencia disponible. Este API utiliza XML para transmitir llamadas de procedimiento remoto (RPC). En JAXB, hemos visto la asociaci6n provista entre un Esquema XML y una clase Java. De un mod0 similar, JAX-RPC define una asociaci6n para llamadas RPC de base XML a interfaces, clases y mktodos Java. Esto permitiri que las llamadas RPC definidas en otros lenguajes Sean asociadas en Java. El API tambiin define la asociaci6n inversa que permite a1 c6digo de programa existente de base Java asociarse a RPC de base XML. Esta asociaci6n inversa t a m b i h se proporciona IDL Java (RMI-IIOP) para convertir el RMI existente basado en aplicaciones a IDL. El grupo experto que trabaja en este proyecto esti estudiando las asociaciones existentes utilizadas en CORBA y RMI-IIOP para alinear las nuevas asociaciones con las existentes. Ademis de estas asociaciones, el API debe ajustarse a las operaciones de marshaling y unmarshaling de argumentos de metodo. El API seri independiente de 10s protocolos y formatos de datos especificos permitiendo la creaci6n de aplicaciones "conectables" como se describen en el API JAXP descrito anteriormente. W3C esti desarrollando un nuevo protocolo XML estindar llamado XP que se ajusta a las llamadas RPC basadas en XML. El API RPC-JAX propuesto proporcionari primordialmente apoyo para XP. Este API seri fitil en la escritura de clientes Java que utilizan servicios Web remotos basados en llamadas de procedimiento remoto. SOAP, sin embargo, proporciona un modo mis generalizado de acceder a un servicio Web.

JAXR es un nuevo API en desarrollo en el Proceso de Comunidad Java (JCP) y el primer borrador phblico fue lanzado el 10 de Agosto de 2001. En la actualidad, existen varios registros de empresa disponibles en el mercado. Para enumerar a l p n o s , 6stos son UDDI, ebXML, I S 0 1 1179, OASIS y eCo Framework. Los API para acceder a estos registros varian considerablemente y dificultan asi la escritura de programas cliente portitiles. La especificaci6n JAXR intente unificar el acceso a estos registros y probablemente a futuros registros, definiendo un nuevo API Java.

Arquitectura
El siguiente diagrama ilustra la arquitectura general. El proveedor de servicios implementa la interfaz para un registro. U n cliente de base Java utiliza entonces el API JAXR para acceder a1 registro utilizando una interfaz Java estindar:

Capitulo 22

Cliente JAXR (API JAXR)

El proveedor de servicios JAXR puede utilizar otros API relacionados con XML como JAXP, JAXB o JAXM para proporcionar compatibilidad XML a 10s registros existentes. El proveedor JAXR es responsable de implementar la especificaci6n JAXR. Esta seria implementada generalmente como una fachada alrededor del proveedor de registro existente. U n cliente JAXR es un programa Java que utiliza el API JAXR para acceder a 10s servicios ofrecidos por el proveedor JAXR.

Objetivos de diseiio
Como hemos mencionado anteriormente, la especificaci6n JAXR todavia sigue como borrador phblico. A1 disefiar este API, se persiguen 10s siguientes objetivos:
U Definir un API Java estandarizado de propositos generales que permita a 10s clientes Java acceder a

una amplia variedad de registros de empresa en uso a travCs del proveedor JAXR Definir una arquitectura de proveedor JAXR conectable para apoyar una variedad de registros

u Proporcionar compatibilidad con las mejores caracteristicas de todos 10s registros dominantes en
lugar de definir el denominador menos comhn de estas caracteristicas
3 Garantizar la compatibilidad con 10s dos registros predominances, ebXML y UDDI, a la vez que

se intenta generalizarlos para ser compatible a otros


d Seguir las norlnns de las especificaciones Java

De este modo, JAXR, cuando estC disponible, resultad htil para la creation de servicios Web de colaboracion que requieren acceso a registros diversificados a travks de c6digo Java.

DespuCs de haber visto las diversas tecnologias relacionadns con 13 creaci6n de servicios Web y con lo que Java ofrece, es momento de aplicar lo que hemos aprendido hasta el momento a la creaci6n de servicios Web.

Capitulo 22
El cliente consigue acceder a1 registro contactando prirnero con el servidor Web que ha irnplementado el servlet o la pagina JSP y utiliza JAXR (por venir) para interactuar con el registro. En la actualidad, se pueden utilizar 1as irnplernentaciones U D D I proporcionadas por diferentes vendedores corno interfaz con el registro. Una vez localizado el servicio, el cliente obtiene el contrato para utilizar el servicio. El contrato describe la interfaz Web especificando 10s rnitodos provistos, 10s parimetros requeridos por cada rnetodo y el valor de retorno, que el cliente puede utilizar para construir la solicitud SOAP.

La interfaz del servicio Web


La interfaz Web es irnplementada en un servlet o en una pigina Web. El cliente crea una solicitud de servicio en un rnensaje S O A P y envia el mensaje a1 servidor Web que actua corno interfaz de usuario para el servicio Web. Cuando el servidor ha recibido el rnensaje SOAP procedente del cliente, procesa el docurnento XML de base S O A P recibido. Podemos utilizar cualquiera de las tecnologias de procesamiento de XML analizadas anteriorrnente para irnplementar 10s mensajes XML. Las tecnologias que podriamos utiliza son:

0 SOAP 0 S O A P con anexos


E I 0

ebXML XMLP (Protocolo XML)

Habitualrnente, el docurnento XML es extraido del mensaje recibido utilizando API SOAP o ebXML. Es posible utilizar JAXM o J A X - W C para procesar un rnensaje XML entrante. Sin embargo, estas tecnologias estan todavia en desarrollo; cuando esten disponibles, podrernos utilizarlas en lugar de 10s API rnencionados.

lmplementar la Iogica de empresa


Una vez que el docurnento XML recibido del cliente ha sido procesado, el servicio Web puede proporcionar a1 cliente el servicio deseado invocando un rnetodo adecuado implernentado en algdn lugar de la ldgica de ernpresa. La localizaci6n de la 16gica de ernpresa depende en gran rnedida de la cantidad de trifico que se espere. Para sitios que n o esperen rnucho trifico, 10s servlets serin adecuados para la irnplernentacion de ldgica de ernpresa, rnientras que para 10s sitios en 10s que se prevea rnucho trifico, seria necesario utilizar EJB para una rnejor reajustabilidad. El servlet en primer plano asume la responsabilidad de la gestion de sesi6n.

lntegrar otros recursos


La logica de ernpresa probablernente necesitari utilizar otros recursos para llevar a cabo la funcionalidad de empresa deseada. Por ejemplo, puede que necesite acceder a una base de datos de en segundo plano o a un sistern; de legado para tornar 10s datos requeridos por una deterrninada operation de empresa. Podria utilizar JDBC para cornunicar con un sisterna de base de datos subyacente. Puede utilizar conectores J2EE para conversar con un sisterna de legado, un JMS para cornunicacidn asincrona con otras aplicaciones capacitadas para el envio y recepcion de rnensajes. Los rnensajes pueden ser construidos utilizando 10s API SOAP, SwA y ebXML analizados anteriorrnente. En el futuro, podra utilizar JAXM o J A X - W C para la rnensajeria.

Devolver resultados a clientes


Cuando la 16gica de empresa ha procesado la solicitud y generado 10s datos deseados, pasa la inforrnacion a1 servlet frontal o componente JSP. El cornponente frontal puede ahora forrnatear el resultado para el

J2EE v servicios Web


cliente integrindolo en un mensaje SOAP. Una vez mis, puede utilizar D O M (a travis de JAXP) para crear un documento XML o, en el futuro, podri utilizar Asociaci6n de Datos Java (JAXB) para crear un documento de este tipo. El mensaje XML empaquetado sera devuelto a1 cliente.

Un sencillo servicio Web


En esta secci6n, vamos a desarrollar un sencillo servicio Web, utilizando el juego de herramientas de servicios Web de IBM. La copia de evahaci6n del juego de herramientas puede descargarse desde el sitio de IBM Alpha Works en http://w.alphaworks.ibm.com/tech/webse~icestoolkit. El servicio Web que vamos a desarrollar ofreceri a1 cliente remoto las cotizaciones de bolsa. Llamaremos a este servicio StockQuoteService. El desarrollo empieza con a1 escritura del archivo Java que implementa la funcionalidad deseada de provisi6n de cotizaciones de bolsa para el simbolo de la bolsa requerido. El servicio expone su funcionalidad con la ayuda de mitodos pbblicos. En la situaci6n actual, definiremos un metodo public0 llamado g e t s t o c k P r i c e ( ) que recibe un argument0 decadena que contiene el simbolo de bolsa solicitado y devuelve la ultima cotizaci6n de bolsa, desde una base de datos, como cadena para el cliente.

Desarrollar el archivo Java StockQuote


El programa fuente para el servicio de cotizaciones de bolsa es el siguiente:

publlc

c l a s ~S t o c k Q u o t e

/ / Cargar e l d r i v e r de l a base de datos static { try i C l a s s . f o r N a m e ("COM. c l o u d s c a p e . c o r e . J D B C D r i v e r " ) r ~ e w I n s t a n c e ( ) ; ) catch (Exception e ) [ e.printStackTrace ( ) ;

/ / E s t e m k t o d o e s e x r s u e s t o como un s e r v i c i o Web p u b l i c S t r i n g g e t s t o c k P r i c e ( S t r i n g syii~tlol) { Connection con = n u l l ; t>oolean r e s u l t = f a l s e ;


S t r i n g u r l = "jdtic: c l o u d s c a p e : c : / j2 s d k l . 3 / c l o u d s c a c a p e D B " ; String price=""; try

i
con
=

DriT~trManager g.e t C o r ~ r ~ e c t i o(ru i r l );

//

Recuperar d a t o s de l a base d e datos Staten1er.t s t m t = con.createStaterr1er1t ( ) ; S t r i n g s q l = "SELECT F R O M stockdetalls symbol t " ' ) " ; R e s u l t s e t r s = s t m t . e x e c u t e Q u e r y ( s q l );
+

WHERE

(stocksymbol="'

/ / Mostrar e l conjuntc de resultados while ( r s . n e x t ( ) ) [ price = rs.getString(2); result= true; break;

Capitulo 22

rs. close ( ) ; stmt .close ( 1 ; catch(Exception e ) [ e.printStackTrace0;

if ( r e s u l t ) [ return price; 1 else { return "Enter a valid

Stock Symbol";

1
1

Antes de ejecutar este cbdigo, necesitari crear una tabla llamada s t o c k d e t a i l s en su base de datos y afiadir a ella algunos registros. Este es el SQL para crear la tabla:
CREATE TABLE stockdetails ( s t o c k s y m b o l V A R C H A R ( 1 0 ) NOT N U L L , stockprice V A R C H A R ( 1 0 ) )

Crear el JAR
El siguiente paso en el desarrollo es compilar y convertir en JAR el archivo de clase creado. Utilice el siguiente comando para crear un archivo JAR llamado s t o c k . j a r :
jar cvf stock. jar StockQuote. class

Generar archivos WSDL


A continuaci6n, generaremos el archivo WSDL que expone el metodo g e t s t o c k p r i c e ( ) de nuestra clase Java como semicio Web. Esto podria significar escribir todo el cbdigo XML. Afortunadamente, el juego de herramientas de IBM proporciona una herramienta para generar el archivo WSDL. Inicie la herramienta ejecutando el archivo w s d l g e n .b a t provisto en la carpeta \bin del juego de herramientas de semicios Web de IBM. Asi, se abre la ventana que mostramos a continuacibn:

WSDL Generation TOOI


Please select the service creation type:

. ... .................. " ..2ava..G!as4


..

r r

EJB Jar File COM Dispatch Interface

J2EE v servicios Web


La herramienta le permite crear una descripci6n de servicio Web desde cualquiera de las interfaces niostradas. Utilizaremos la opci6n Java Class para generar la descripci6n para nuestro servicio Web. Haga clic en Next (Siguiente) para pasar a la siguiente pantalla del asistente:

Java Class WSDL Ctnrration


Class Name
I~tntit~uote

F Yfi/ro~IProJa\raSeruenCh227slockjar

Classpath

P
I
Properly Name

Output Filename

r
I
Value

n
I'

En el canipo Class Name (Nombre de la clase) introduzca StockQuote y e n Classpath, facilite la ruta completa del archivo stock . j a r . Acepte el nombre del archivo de salida por defecto, per0 aseglirese de que sale en el mismo directorio en que ha creado el archivo de clase. Las propiedades del servicio se presentan en la tabla como se muestra en la captura de pantalla. Haga clic en Next para pasar a la siguiente pantalla. En esta pantalla, veri In lista d e metodos descubiertos por la herramienta:

Capitulo 22

,void watl(long,mt) vo~dka~t(lo~g! Class getclass0

-I
I1 7 1

Back

Desplace hacia abajo la lista de rnitodos hasta encontrar el mktodo getstockprice ( ) . Seleccione este metodo y haga clic en Next. La siguiente pantalla le da la oportunidad de confirmar sus opciones antes de que la herramienta genere el archivo WSDL:

Confirm vour chblces

;Urappering source: ScockOuocc ,TD USDL docment: c:\Uron\ProJavaServer~Ch22\Swck(luocc~Setvi


I

Haga clic en Finish (Finalizar) para generar el archivo WSDL. DespuCs de la creaci6n efectiva del archivo, emerge un mensaje en la pantalla para indicar que la operaci6n ha sido realizada con kxito:

1176

J2EE y servicios Web

Corno parte del proceso de generaci6n de WSDL, se crearin 10s siguiente archivos en la presente carpeta:

El archivo StockQuote Service.wsdl


El archivo generado S t o c k Q u o t e - S e r v i c e . w s d l es el que rnostrarnos a continuaci6n:

<service r ~ a m e = " S t o c k Q u o t eService", <documentation>


I R M MSTK 2 . 0
q e n e r a t e d service d e f i n i t i o n

file

</dacumentatior~>
<port

binding="StockQuote ServiceBinding" name="StockQuote ServiceFort"> <soap: a d r e s s l ~ ~ c a t i o n = " h t t/p /l :o c a l h o s t : POF!O/snap/servlet/rpcrouter"/>


</port>

</service>

Corno podernos ver en el listado anterior, el archivo WSDL declara un servicio llarnado

s t o c k ~ u oe-s t ervice.Tarnbi6n declara la localization del servlet r p c r o u t e r que se utiliza para


encaminar las solicitudes del servicio hacia la clase Java apropiada. Necesitari rnodificar este archivo

WSDL para establecer la localizaci6n para el archivo de la interfaz en la carpeta actual. Modifique el
atributo l o c a t i o n de laetiquetaimport delsiguiente modo:

Ahora analizaremos el archivo generado de la interfaz.

El archivo StockQuote Service-interface.wsdI


La herrarnienta w s d l t o o l genera el archivo de la interfaz del servicio, cuyo listado es el siguiente:

Capitulo 22
<?xml version="l. 0" encoding="UTF-8"?> <definitions name="StockQuote Service" targetNamespace="http://www.stockquoteservice.com/StockQuote-ir~terface" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlr~s:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tr~s="http://www.stockquoteservi~e.com/StockQuote" xmlns:xsd="http://www.w3.org/l999/XMLSchema">

<binding r~ame="StockQuoteServiceBinding" type="StockQuote Servicew> <soap: binding style="rpcM trar~sport="http://schemas.xmlsoap.org/soap/http"/> coperat ion narne="getStockPrice"> <soap:operation soapActior~="urn:stockquote-service"/> <input> <soap: body encodingStyle="http: //schemas .xmlsoap. org/soap/er~coding/" namespace="urr~:stockquote-service" use="encoded"/> </input> <output> <soap: body encodingStyle="http: //schemas. xmlsoap. orq/soap/er~coding/" namespace="urn:stockquote-service" use="encodedW/> </output> </operation> </binding>

C o m o se puede ver en el listado anterior, 10s parimetros de entrada aparecen primero. El tip0 de pardmetro de entrada es una cadena:

J2EE y servicios Web


Despuis, se declara el tip0 de retorno del mitodo:

A continuaci6n, la operacibn se declara como sigue; el nombre de la operaci6n es g e t s t o c k P r i c e .


Observe que iste es el mitodo de nuestra clase Java que deseamos exponer como sewicio Web. El mktodo requiere un parimetro de entrada como se define en el nombre I n g e t S t o c k P r i c e R e q u e s t y devuelve unasalida tal y como esti definido por el n o m b r e ~ u t g e t S t o c k ~ r i c e ~ e s p o n s e :

Finalmente, la etiqueta b i n d i n g define el estilo utilizando la siguiente instrucci6n. El estilo indicado es una llamada de procedimiento remoto y utiliza HTTP para el transporte:

La etiqueta b i n d i n g enumera a continuaci6n ]as operaciones. En nuestro caso, s61o tenemos una operaci6n expuesta. El estilo de codificaci6n para parimetros de entrada y de salida se declara aqui.
A continuaci6n, generaremos la clase proxy para el uso de nuestra aplicaci6n de cliente.

Generar la clase proxy


El juego de herramientas de IBM viene a recatarnos en este momento proporcionindonos una utilidad para generar una clase proxy para nuestro sewicio Web. Ejecute el archivo p r o x y g e n .b a t para invocar la utilidad de generaci6n del proxy:

El fichero de procesamiento por lotes genera un archivo llamado ~ t o c k ~ u o t e ~ s e r v i c e P r . oj x ay va y tambiin lo compila. En el siguiente paso, necesitamos implementar el sewicio en el sewidor Web.

Registrar el servicio en el servidor Web


Utilizaremos el sewidor integrado Websphere que acompafia al juego de herramientas WSTK para probar nuestro sewicio Web. Antes de iniciar el sewidor, aseglirese de afiadir el archivo s t o c k . j a r y su controlador de base de datos a su ruta de clase. Inicie el sewidor Web con el siguiente comando:

Capitulo 22
3PJSTK -H O M E ' $ \ b i r ~ \ w e b s [ . ~ h e r e 1-un

A continuaci6n, abra el navegador e introduzca el siguiente URL:


http://localhost:8080/s0a p/ad min/

Asi se inicia la utilidad de administraci6n para gestionar sus servicios Web:

What do you want to do today?

La utilidad de administraci6n le permite gestionar y catalogar 10s servicios. Para irnplernentar nuestro servicio, haga clic en el b o t h Deploy (Implementar). Aparece la siguiente pantalla:

J2EE y servicios Web

Deploy a Service
.-

---

Service Deployment Descriptor Template

or

User-Defined Provider Type, Enter FULL Class Name

Number of Options. 1

Key

Value

Necesitari configurar algunos parametros en la pantalla:


Q ConfigurelDenurn: s t o c k q u o t e - s e r v i c e

O Configure Scope (Alcance) en Application (Aplicacibn)


0 0

Configure Methods (Mdtodos) en g e t s t o c k p r i c e Configure Provider Type (Tipo d e proveedor) en Java (predeterminado)

Q Configure Java Provider

- Provider Class (Proveedor Java- Clase Proveedor) en S t o c k Q u o t e

Para el resto de 10s campos, acepte 10s valores por defecto. Desplace la pantalla hacia abajo y haga clic en el b o t h Deploy. Si se ha implementado con ixito, aparece en la pantalla un mensaje como 6ste:

Capitulo 22

II

Senrice urn:stockquote-service deployed.

Una que el servicio se ha implementado con kxito, el siguiente paso es escribir el programa cliente para poner a prueba el servicio Web.

Desarrollar un cliente
Escribir el cliente para nuestro servicio Web es muy sencillo. El programa cliente utiliza la clase proxy generada para obtener referencia a1 objeto de servicio remoto e invoca sobre 61 el mktodo deseado. El c6digo cliente es el siguiente:
import S t o c k Q u o t e S e r v i c e P r o x y ;
public

class S t o c k c l i e n t

I
{

public static void r n a i n ( S t r i r ~ g [ ] a r g s )

Stock( / / In? Strirr~ / / Imy Syster

1 catch(

S y s t e n.......

I
)

J2EE v servicios Web


El programa cliente es una aplicacibn basada en una consola Java. El metodo main ( ) crea una instancia del objeto proxy que representa el servicio Web remoto. El mitodo del servicio remoto es entonces invocado sobre el objeto proxy creado. El mitodo se ejecuta en el equipo remoto y devuelve un resultado a1 cliente. El programa imprime el resultado en la consola del usuario. La comunicacibn entre el cliente y el servidor se lleva a cab0 utilizando SOAP. Para ejecutar la aplicacibn, necesitari 10s siguiente en su ruta de clase:

O El archivo JAR SOAP


0 El archivo JAR Xerces 0

El archivo JAR JavaMail

O El archivo JAR de Activacibn

A partir de este sencillo ejemplo, puede ver que crear servicios Web con la ayuda de las herramientas adecuadas no es tan dificil como suena en 10s anilisis tebricos.

Crear servicios mas inteligentes


Como 10s servicios Web son creados utilizando tecnologias neutras respecto del vendedor, con XML como medio de transporte de datos, es ficilmente posible integrar servicios mis pequefios (de micronivel) en un servicio de mayores dimensiones (de macro-nivel). Cuando se crea un servicio de macronivel de este tipo, surgen otras cuestiones como seguridad, autentificacibn, control de transacciones, etc. N o s d o eso sino que, en lo referente al consumidor, estos servicios deben estar disponibles de forma transparente (del mismo modo que pretendemos hacer ahora con aplicaciones estindar). Simplemente imagine una situacibn en la que estemos utilizando un servicio de macro-nivel que, a su vez, utiliza varios servicios de micro-nivel provistos por una serie de terceros. Como seguimos recorriendo 10s diversos sitios mientras utilizamos este macro servicio, si tuvikramos que registrarnos en cada sitio con nuestro nombre de usuario y contraseiia, la experiencia de utilizar este servicio seria muy frustrante. En el peor de 10s casos, si hubieramos creado un nombre de usuario y una contraseha diferentes para cada sitio, seria incluso mis frustrante intentar recordar todos 10s nombres de usuario y todas las contrasefias y utilizarlas cada vez en el lugar adecuado. Este problema podria resolverse si el contexto de registro fuera guardado en alg6n lugar y compartido por cada sitio que visitiramos. Ademis del contexto de registro, 10s sitios pueden precisar el uso de contextos de sesibn para proporcionarle una rica experiencia mientras navega. Asl' aparece un nuevo concept0 llamado contexto compartido.

Contexto compartido
U n sewicio Web necesita recordar algunas cosas sobre el consumidor antes de proporcionar una experiencia personalizada. Esto se conoce como contexto. Este contexto puede incluir la identidad,

localizaci6n, lenguaje elegido, informaci6n personal, etc. del usuario. A1 crear un servicio de macro-nivel, esta informaci6n de contexto puede ser compartida con otras partes implicadas en la provisi6n del servicio; por supuesto, con 10s permisos pertinentes obtenidos del consumidor. En la actualidad, no hay normas disponibles para la creaci6n de contextos compartidos. Microsoft ha anunciado una arquitectura centrada en el usuario y ha establecido un conjunto de servicios Web XML, cuyonombrec6digoes "HailStorm" (vkasehttp: / / w w w . m i c r o s o f t .c o m / n e t / h a i l s t o r m . a s p para mis detalles), donde un particular puede almacenar informaci6n personal con este servicio. Esta informaci6n puede ser compartida por otras aplicaciones que se ajusten a Hailstorm. Sin embargo, estari estrechamente en la plataforma de Microsoft. Las especificaciones para crear un contexto compartido no deben proceder de un h i c o vendedor y un servicio de este tip0 no debe ser de propiedad. Si la soluci6n es abierta, contribuiri a la creaci6n de servicios Web interoperables. Asi, 10s particulares que permitan el uso compartido de sus contextos deben asegurarse de la seguridad y privacidad de la informaci6n de entrada. Estas normas estin por Ilegar.

Servicios Web inteligentes


U n servicio Web inteligente es aquel que comprende el contexto de un cliente solicitante y comparte ese contexto con otros servicios. U n servicio Web inteligente puede obtener y utilizar informaci6n sobre diversas circunstancias de situaci6n. Por ejemplo, puede obtener contextos para las siguientes situaciones:

o Identidad del consumidor del servicio o Rol del consumidor o Preferencias individuales, si las hay
O

Politica de seguridad del consumidor

o Politica de privacidad del consumidor o Politica de empresa asociada a1 consumidor


0

Localizaci6n del consumidor Dispositivo cliente utilizado por el consumidor Historial Cualquier acuerdo existente entre el consumidor y el actual proveedor del servicio Web

O O O

El servicio Web inteligente, despuks de obtener esta informaci6n de contexto, proporcionari un servicio ampliamente personalizado a1 consumidor y puede compartir esta informaci6n son servicios Web colaboradores. Muchos sitios Web de hoy en dia ofrecen personalizaci6n; estos sitios mantienen la informaci6n de contexto en formatos de propiedad. N o existe un estindar para compartir la informaci6n de contexto con otros usuarios.

La iniciativa Sun ONE


En Febrero de 2001, Sun Microsystems anunci6 su arquitectura para crear servicios Web inteligentes, interoperables. La arquitectura se llama Sun O p e n N e t Environment (Sun O N E ) y hace frente a cuestiones importantes relacionadas con la privacidad, la seguridad y la identidad. Define pricticas y convenciones para crear servicio Web inteligentes interoperables. Puede adaptarse a una amplia variedad de

J2EE y servicios Web


dispositivos de cliente desde dispositivos capacitados para PDA y WAP hasta grandes granjas Web. Puede encontrar rnis detalles en http://www.sun.com/sunone/. La arquitectura Sun O N E esti basada en tecnologias XML y Java y en otras norrnas de infraestructura nuclear. Estas tecnologias y norrnas incluyen D O M , ebXML, HTTP, JAXM, JDBC, JSP, LDAP, SOAP, SSL, WML, WSDL, XHMTL, Analizadores XML, Esquernas XML, XPATH, XSLT y otros rnenciohados anteriorrnente en el capitulo.

Analisis de la arquitectura funcional


La arquitectura funcional propuesta por Sun O N E esti descrita en el siguiente diagrarna:

t
Cualquier Dispos~tivo '4

~ s t es a unavisi6n funcional de alto nivel de la arquitectura. El cornponente de Creaci6n y Ensamblaje de Servicios hace referencia a1 proceso de creaci6n de servicios de micro-nivel y a su agregacion en un servicio de macro-nivel de cornposici6n. Los servicios de micro-nivel son creados utilizando entornos integrados de desarrollo, editores sensibles al contexto y las tecnologias y API nucleares analizados en la secci6n anterior. El ensarnblador utiliza diversos micro-servicios de este tipo para crear un servicio de macro-nivel. El ensamblador tarnbikn define las politicas de seguridad, las politicas sensibles al contexto y otros parirnetros de periodo de ejecucion para el servicio. Las politicas de seguridad estin configuradas en el bloque de Identidad y Politics. El bloque de Aplicaci6n y Servicios Web ilustra 10s servicios Web irnplernentadosados. Los servicios Web pueden irnplernentarse en cualquier plataforrna y dispositivo, desde un ordenador de bolsillo hasta un servidor rnultiprocesador de alto nivel. El servicio puede estar cornpuesto de rnuchos micro servicios. El bloque de Contenedor de Servicios indica un contenedor en el que se implementan 10s servicios. El contenedor puede ser una sencilla rniquina de servlet o un servidor de aplicaci6n rnis cornplejo que irnplernente tambikn cornponentes EJB. Estos contenedores proporcionarin diversos servicios a1 servicio Web corno gestion de transacciones, seguridad, concurrencia, etc. La Plataforma designa el sisterna operativo o el equipo virtual en la que se ejecuta el contenedor. El contenedor obtiene 10s servicios del nivel del sisterna operativo desde este bloque. El bloque de Provisi6n de Servicios indica un vinculo de cornunicaci6n con el cliente y es responsable de todas las interacciones con el cliente. Este bloque analizari las solicitudes XML procedentes del cliente y forrnateari la salida XML para el cliente. Este bloque puede actuar de interfaz con clientes corno un ordenador de bolsillo, un dispositivo capacitado para servicios WAP, otro servicio Web, etc. Por ultimo, el bloque de Integraci6n de Servicios indica la conexion a 10s recursos en segundo plano corno bases de datos, sisternas de legado con conectores JZEE, etc.

Capitulo 22

Arquitectura de servicios Web inteligentes


La arquitectura propuesta para proporcionar servicios Web inteligentes esti descrita en el siguiente diagrama:

A Solicitud HTTP Respuesta HTTP

Como se puede ver en el diagrama, 10s servicios Web inteligentes serin implementados afiadiendo varios bloques a la arquitectura que capturen y utilicen informaci6n sensible a1 contexto. Son 10s que resumimos a continuacion:
O

Provisi6n inteligente

U Gesti6n inteligente 0

Proceso inteligente

O Politica inteligente

J2EE y servicios Web Provision inteligente


El modulo de orovisi6n intelieente facilita la aereeaci6n de micro servicios en un servicio de macro nivel. w w w Tarnbikn proporciona adaptaci6n y personalizaci6n para el cliente. El rn6dulo obtiene la inforrnaci6n de contexto a partir del canal de entrega, personaliza la respuesta a1 cliente y la entrega a travks del canal de entrega. Se adapta a una arnplia variedad de dispositivos de cliente y forrnatos de presentaci6n que incluyen HTML, XHTML, WML, (Wireless Markup Language) y VoiceXML. Tarnbikn es responsable de transforrnaciones de contenido y utiliza XSLT para estas transforrnaciones.

Gestion inteligente
La funcidn de gesti6n inteligente es responsable de la gesti6n global del servicio Web y garantiza la privacidad de 10s datos cornpartidos a1 consurnidor del servicio. Tarnbikn ofrece seguridad y controla el acceso utilizando 10s derechos de acceso definidos para el consurnidor. Adernis de esto, este rn6dulo tarnbikn es responsable del registro y la disponibilidad adecuada del servicio a travks del uso de un registro de servicios. Tarnbikn garantiza la ejecuci6n correcta del acuerdo de suscripci6n para el consurnidor y asegura a1 consurnidor una minima calidad de servicio gracias a1 acuerdo de servicios establecido entre las dos partes. Obtiene las politicas de gesti6n y de periodo de ejecuci6n del rn6dulo de politicas inteligentes y garantiza la adecuada irnplernentaci6n de las rnisrnas.

Proceso inteligente
Este rn6dulo es responsable de la gesti6n del proceso y perrnite la rnodificaci6n de secuencias en un servicio Web basado en el actual contexto de usuario.

Politica inteligente
Este rn6dulo obtiene de un registro la inforrnaci6n de politica y del usuario rnis reciente, posiblernente utilizando LDAP. Utiliza el servicio de autentificaci6n provisto por el proveedor de servic~os PKI (Public Key Infrastructure) y autoriza consecuenternente el uso del servicio a1 cliente. Puesto que la inforrnaci6n se obtiene en el periodo de ejecuci6n, las politicas de seguridad pueden carnbiar dependiendo del contexto actual del usuario. Este rn6dulo es responsable de adaptar dinirnicarnente el servicio basado en el contexto actual.

Apoyo del vendedor a servicios Web


Con la creciente popularidad de 10s servicios Web, 10s vendedores de servidores de aplicaci6n han cornenzado a dar apoyo a la creaci6n de servicios Web en sus productos. Estos vendedores incluyen a BEA, IBM (naturalrnente), Silverstream y Capeclear. BEA clasifica 10s servicios Web en dos categorias: sencillos y cornplejos.

Sewicios Web sencillos


U n servicio Web sencillo proporciona sirnplernente un tip0 de funcionalidad solicitud/respuesta y no es compatible con transacciones ni proporciona seguridad sofisticada. Estos servicios tienen las siguientes caracteristicas:

Capitulo 22
El cliente invoca el servicio en un servidor remoto y el servidor remoto devuelve la respuesta al cliente. R P C y base de mensaje. El servicio implica invocar un procedimiento remoto y utiliza 10s mensajes XML para la solicitud y para la respuesta. N o transaccional. C o m o estos servicios conllevan una sencilla solicitud seguida de una respuesta a1 cliente, el servicio, por naturaleza, se convierte en no transaccional. U n servicio transaccional requeriria la participaci6n de otros recursos y/o servicios Web. Seguridad Web. El servicio s610 utiliza la seguridad bisica proporcionada por el servidor Web, como la autentificaci6n.

Sewicios Web complejos


U n servicio Web complejo, por otro lado, proporciona la estructura para la colaboraci6n de empresa-aempresa y la gesti6n de procesos de empresa. Estos servicios tienen las siguientes caracteristicas:
O Multiparte

U n servicio Web complejo implica a mliltiples socios. Por ejemplo, si el inventario del almackn cae por debajo de un cierto umbral, puede enviarse una solicitud de cifras (RFQ) a 10s mhltiples proveedores.
0

Colaboracion v , fluio , de trabaio Todas las partes implicadas en el servicio colaborarin y contribuirin en el control del flujo de trabajo definido en el servicio Web. Puesto que el servicio Web complejo implica a mliltiples socios y conlleva la agregaci6n de diversos servicios de micro nivel, debe ejecutarse bajo control de transacci6n que se extienda a varios servidores.

0 Transaccional

Seguridad sofisticada El servicio Web complejo utiliza firmas digitales para la autentificaci611, control de acceso, implementaci6n de politicas de seguridad y no repudio de forma que ninguna parte pueda rechazar una transacci6n de empresa completada. Estado conversacional U n servicio complejo mantiene el estado de conversaci6n con el cliente, obtiene el context0 y puede compartir esto con servicios de socios colaboradores. Basados e n acuerdos El servicio complejo esti basado en 10s acuerdos entre las dos partes. Esto es similar a 10s servicios inteligentes analizados anteriormente.

En este capitulo, hemos analizado la tecnologia emergente conocida como servicios Web. La creaci6n y uso de servicios Web ha atrapado la mente de muchos desarrolladores y vendedores. Los servicios Web

1188

J2EE y servicios Web


pueden ser creados utilizando diferentes tecnologias. Hemos visto que las siguientes tecnologias forman parte del instrumental irnplicado en la creaci6n de servicios Web:
O SOAP O SOAP con anexos (SwA) O WSDL

UDDI Todas las tecnologias anteriores estin basadas en XML y contribuyen en la creaci6n de servicios neutrales en relaci6n con el vendedor que pueden interoperar con otros servicios.

Elegir una implernentacion JZEE


En este capitulo, analizaremos aquello que se encuentra en el nucleo de una implementaci6n J2EE y veremos c6mo 10s vendedores emprenden la implementaci6n de las normas J2EE. Destacando cualquier funcionalidad afiadida de valor, examinaremos la competencia entre varios vendedores. Asimismo, analizaremos algunos elementos clave en comparaci6n que se deben tener en cuenta antes de tomar una decisi6n tecnobgica o de compra, y revisaremos y aprenderemos la curva de aprendizaje asociada a1 uso de una implementaci6n J2EE. Es importante destacar que las normas J2EE n o definen c6mo deben implementarse 10s elementos de una implementaci6n J2EE. De hecho, 10s vendedores son libres de crear productos a medida que observen una determinada necesidad en el mercado. Las opciones de implementaci6n mds comunes en el mercado hoy en dia son las miquinas de servlet y 10s servidores de aplicaci6n. Dependiendo del proyecto, puede necesitar uno o ambos. Se espera que 10s servidores de aplicaci6n tengan un equipo de servlet en el contenedor Web y un contenedor Enterprise JavaBeans (EJB). Los vendedores se inclinan por la creaci6n de una separation entre el contenedor Web y el contenedor EJB con el objetivo de poner en prdctica una separaci6n entre la capa de presentaci6n y la capa de 16gica de empresa.

Servidores de aplicacion
La plataforma J2EE representa un unico estdndar para la implementaci6n de aplicaciones de empresa. H a sido disefiada a travks de un proceso abierto, comprometiendo a una variedad de vendedores de procesamiento informltico de empresa para asegurar que cubre la gama m6s amplia de posibilidades de requisitos de aplicaci6n de empresa. La plataforma J2EE estd disefiada para proporcionar compatibilidad cliente para el desarrollo de aplicaciones de empresa. Estas aplicaciones se configuran como un nivel de cliente para proporcionar la interfaz de usuario, uno o m6s m6dulos de nivel medio que proporcionen servicios de cliente y 16gica de empresa para una aplicaci6n, y 10s sistemas de informaci6n de empresa de segundo piano que proveen la gesti6n de datos.

Capitulo 23
Los componentes de nivel rnedio norrnalmente se ejecutan en el interior del servidor de aplicacibn, que puede rnanejar todos 10s servicios de nivel de sistema, de rnodo que 10s desarrolladores pueden concentrarse en la construcci6n de componentes de 16gica de ernpresa. El nivel medio es compatible con 10s servicios cliente a travCs de una capa llamada contenedor Web en el nivel Web. Los contenedores son sistemas que proporcionan u n entorno estandarizado de periodo de ejecuci6n para semlets, componentes, etc., proporcionando asi 10s semicios que ofrecen estos objetos y liberando a1 programador de la tediosa y compleja tarea de conectar applets a Internet. El nivel Web es el area rnis apropiada para almacenar la 16gica de presentation. Es compatible con servicios de cornponentes de bgica de empresa a travCs de EJB y contenedores en el nivel EJB. Los vendedores han creado productos que abarcan el contenedor Web y el contenedor EJB. Estos productos se conocen corno senidores de aplicacion. En teoria, 10s componentes pueden esperar que estos servicios estCn disponibles en cualquier plataforrna J2EE de cualquier vendedor. Los contenedores son compatibles con la gesti6n de transacci6n y de ciclo de vida para cornponentes EJB, asi corno servicios de busqueda y otros servicios. Los contenedores tarnbiCn proporcionan acceso estandarizado a sisternas de informaci6n de ernpresa y a bases de datos a travCs de JDBC. Adernis, proporcionan rnecanisrnos para seleccionar comportarnientos de aplicaci6n en el periodo de ensarnblaje e irnplernentaci6n. Se consigue con el uso de descriptores de implementaci6n que utilizan etiquetas XML perfectarnente definidos. Los descriptores de irnplernentaci6n son una de las ireas en las que diferentes vendedores tienen pequeiias diferencias entre productos. Por ejernplo, el descriptor de irnplernentacion adicional (en oposici6n a1 definido por J2EE) de un servidor de aplicacion IBM sera ligerarnente diferente a1 del servidor de aplicaci6n BEA. Algunas de las funciones pueden ser configuradas durante el periodo de implernentaci6n, como las cornprobaciones de seguridad, 10s controles de transacci6n y otras responsabilidades de gestion. Dependiendo del producto y del vendedor, la cantidad de RAM de su sisterna configurarse para procesos de sisterna y procesos de usuario. El terrnino servidor de aplicacibn, se asigna a un producto que implernenta el estindar J2EE y ofrece un contenedor Web y un contenedor EJB, corno rninirno, ernpaquetado corno software de servidor. Este producto debe ajustarse a una version de las norrnas J2EE, preferiblernente la dtirna, y debe poder proporcionar:
0 Contenedores EJB y Web U n entorno para aplicaciones basadas en cornponentes para asociarse ficilmente a la funcionalidad deseada de la aplicaci6n. 0 Comportamiento de componente

Para capacitar 10s cornportarnientos del periodo de ensarnblaje e irnplernentacion. Los componentes pueden esperar la disponibilidad de servicios en el entorno de periodo de ejecuci6n y conectarse a otros cornponentes proporcionado un conjunto de interfaces bien definidas. Como resultado, 10s cornponentes pueden ser configurados para un cierto tip0 de cornportarniento en el periodo de ensarnblaje o irnplernentaci6n de la aplicaci6n sin ningGn requisito de recodificaci6n. 0 Reajustabilidad Los contenedores J2EE deben proporcionar un mecanisrno compatible con el reajuste sirnplificado de aplicaciones distribuidas, sin requerir eingfin esfuerzo por parte del equipo de desarrollo de la aplicaci6n. La operaci6nde agruparniento o clustering es una de las funciones utilizadas para cubrir este requisito estindar. 0 Integraci6n con sistemas de empresa existentes Puede realizarse con una serie de API estindar que deben ser apoyados en una irnplernentaci6n J2EE:

Elegir una implernentacion J2EE


0 API JDBC para acceder a datos de relacionales de Java 0 Java Transaction API ('JTA) para gestionar y coordinar transacciones en sistemas

heterogkneos de informacion de empresa. Un buen ejemplo podria ser conectar transacciones que tengan lugar en un sistema de base COKBA con un sistema J2EE conectado a un sitio Web.
O

API Java Naming and Directory Interface (JNDI) para acceder a informaci6n en servicios de nombrado y directorio de empresa. API Java Messaging System (JMS) para enviar y recibir mensajes a travis de sistemas de mensajeria como IBM M Q Series o TIBCO Rendezvous.

API JavaMail para enviar y recibir e-mail.

0 API Java IDL para invocar servicios CORBA. 0

Servicios de seguridad como el Servicio de Autentificacih y Autorizaci6n Java (JAAS).

Aunque la especificaci6n J2EE define 10s contenedores de componentes que deben ser compatibles y 10s API que deben estar disponibles, no intenta especificar o restringir la configuraci6n de estos contenedores, ni la disposicion de 10s servicios. Asi, ambos tipos de contenedores pueden ejecutarse en una linica plataforma o un entorno distribuido. Tanto BEA WebLogic como IBM Sphere, por ejemplo, tienen un contenedor Web y un contenedor EJB en su producto de servidor de aplicaci6n. Otros vendedores tienen un enfoque similar. El siguiente diagrama muestra la disposicion habitual de un product0 de servidor de aplicaci6n:

Pila Minima de Servidor de Aplicacion

Pagina JSP

Sesion

Controlados Entidad

JPSE

JPSE

Es importante observar que un servidor de aplicaci6n esti compuesto por una colecci6n de servicios, contenedores y tambiin por la implementaci6n J2SE, ademis de 10s articulos relacionados con J2EE. Juntos conforman el conjunto de servicios destinados a apoyar las especificaciones J2EE. ~ s t no e es, en absoluto, el linico modo, y ni siquiera el mejor; sin embargo, es el enfoque de uso mas extendido del mercado. Como veremos, una vez cubiertos 10s requisitos minimos en tkrminos de

Capitulo 23
implementation, 10s vendedores utilizan otros servicios para conseguir que sus productos resulten mis atractivos. Recuerde tambikn que su servidor de aplicaci6n "hecho y derecho" puede no ser necesario para completar un proyecto; quizis no necesite que toda la funcionalidad estC presente en 10s servidores de aplicaci6n.
En ocasiones, el contenedor por si solo puede proporcionar 10s servicios necesarios, por ejemplo, un equipo de servlet para representar piginas JSP. BEA WebLogic Express es un producto de rango comercial que incluye una miquina de servlet ademis de otras caracteristicas. Sin embargo, no incluye el contenedor Web, haciendo que el producto sea mis adecuado para el trabajo en primer piano en arquitecturas Web. En la siguiente secci6n, dirigiremos nuestra atenci6n hacia la implementacidn real de la e~~ecificacidn J2EE.

Implementation de las especificaciones J2EE


La especificaci6n J ~ E E es creada y revisada bajo el Proceso de la Comunidad Java (http://www.jcp.org/) por un grupo de expertos industriales representando a cornpahias como BEA, Bluestone Software, Borland, Bull S.A, Exoffice, Fujitsu Limited, Gemstone Systems, IBM, Inline Software, I O N A Technologies, IPlanet, jGuru, Orion Application Server, Persistence, P O E T Software, Silverstream, Sun y Sybase.

La norma J2EE se define a travCs de un conjunto de especificaciones relacionadas:


O

Especificaci6n J2EE: define las responsabilidades de 10s desarrolladores de componentes y de 10s vendedores de servidores EJB y contenedores. Especificacidn de servlet: proporciona a 10s desarrolladores Web un mecanismo sencillo, consistente para ampliar la funcionalidad de un servidor Web y para acceder a 10s sistemas de empresa ya existentes. Especificaci6n de JavaServer Pages USP): permite a 10s desarrolladores y disefiadores Web desarrollar ripidamente y mantener ficilmente piginas Web dinimicas, ricas en information que alivian 10s sistemas de empresa existentes.
I

Juntas, estas e~~ecificaciones definen 10s componentes clave de arquitectura requeridos en una implementaci6n J2EE. Ademis de las especificaciones, hay otros ofrecimientos disponibles para ajustarse a las normas JZEE, incluido J2EE Compatibility Test Suite (CTS) y el DSK de J2EE. Lo Gltimo en compatibilidad esti disponible en Sun en http://java.sun.corrJj2ee/compatibiIity.html y en http:// developer.java.sun.corrJdeveloper/technicaIArticles/J2EVbuild/. El CTS de J2EE contribuye a maximizar la portabilidad de las aplicaciones validando la adaptaci6n de la especificacion de un producto de la plataforma J2EE. CTS pone a prueba la conformidad con 10s API de extensi6n estindar de Java que n o estin cubiertos en Java Conformance Kit (JCK). Ademis, pone a prueba la capacidad de una plataforma J2EE para ejecutar apli.caciones estindar de extremo a extremo. SDK de J2EE pretende alcanzar varios objetivos. Primero, proporciona una definici6n operativa de la plataforma JZEE, utilizada por vendedores como "referente de oro" para determinar quC debe hacer su producto en determinadas circunstancias de aplicaci6n. Los desarrolladores pueden utilizarlo para verificar la portabilidad general de una aplicaci6n (asi como la portabilidad entre servidores de aplicaci6n) y se utiliza como plataforma estindar para ejecutar el CTS de J2EE.

Elegir una irnplementacion J2EE


Otra funcion importante de SDK de J2EE es proporcionar a la comunidad de desarrolladores una implementaci6n de disponibilidad libre de la plataforma J2EE para contribuir a acelerar la adopci6n del estindar J2EE. Aunque no se trata de un producto comercial y sus tkrminos de licencia prohiben su uso comercial, SDK de J2EE puede descargarse de forma gratuita, en forma binaria o de c6digo fuente, para su uso en el desarrollo de demos de aplicacibn y prototipos. Para mis detalles, vaya a http://java.sun.comj j2ee/download. htrnl. La especificacion J2EE no requiere que un producto J2EE sea implementado por un linico programa, un unico servidor o incluso un hnico eouiwo. En u general. las esvecificaciones n o describen la particion de servicios o funciones entre miquinas, servidores o procesos. Siempre que se cumplan 10s requisitos de las especificaciones, 10s vendedores de productos J2EE pueden separar la funcionalidad de diferentes formas para una determinada aplicacion o herramienta. U n producto J2EE debe poder desplegar componentes de aplicacion que se ejecuten con semintica descrita por la especificaci6n. IBM y BEA implementan la funcionalidad de formas diferentes, per0 ambos siguen muy de cerca las especificaciones J2EE.
1

U n producto J2EE muy sencillo puede ser provisto como un unico Equipo Virtual Java compatible con componentes Web y beans de empresa en un contenedor. U n tipico producto J2EE de bajo extremo sera compatible con applets en uno de 10s navegadores populares, clientes de aplicacibn en su propio Equipo Virtual Java y proporcionari un unico sewidor compatible con componentes Web y beans de empresa. La especificacion J2EE describe un conjunto rninimo de instalaciones que deben proporcionar todos 10s productos J2EE. La mayoria de productos J2EE proporcionaran instalaciones mis alli del minimo requerido por esta especificacibn. Esta especificacibn incluye algunos limites a la capacidad de un producto para proveer extensiones. En particular, incluye las mismas restricciones que J2SE sobre extensiones de API Java. Puede que un producto J2EE no afiada clases a 10s paquetes de lenguaje de programacion Java incluidos en esta especificacion y puede que no afiada mktodos o que altere firmas de las clases especificadas. Este paso garantiza que un EJB desarrollado para un proyecto seghn un requisito especifico, como apoyo transaccional completo durante una determinada operacion de bgica, pueda ejecutarse en diferentes implementaciones de vendedor J2EE sin ser recodificado. Sin embargo, se permiten muchas otras extensiones. U n producto J2EE puede proporcionar API Java adicionales, otros paquetes opcionales Java (JavaHelp, Java 3D, Java MediaFramework, etc.) u otros paquetes (esto incluye algunos paquetes de acceso anticipado como Java Management). U n producto J2EE puede incluir compatibilidad con protocolos o sewicios adicionales no especificados en las normas. U n producto J2EE puede ser compatible con especificaciones escritas en lenguajes distintos de Java o con la conectividad con otras aplicaciones de plataforma. Esto proporciona espacio para una amplia competencia en distintos aspectos de calidad de servicios. Los productos ofrecerin diferentes niveles de rendimiento, reajustabilidad, facilidad de uso, disponibilidad y seguridad. En algunos casos, las especificaciones J2EE requieren niveles minimos de servicios. Futuras versiones de la especificacion quizis permitan a las aplicaciones describir 10s / requisitos en estas ireas. Sun ha puesto a disposition (en formato fuente y en formato binario) una aplicaci6n Web de referencia J2EE, Java Pet Store Application. Cualquier implementaci6n de la norma J2EE procedente de alguna de las mis conocidas compafiias como BEA, IBM, H P , Oracle y otras, debe poder instalar y ejecutar Pet Store. Esta aplicacion Web de referencia puede descargarse enhttp://java.sun.comjj2ee/download.htrn#blueprints y ejecutarse en cualquier sewidor de aplicacion certificado que se ajuste a J2EE el cien por cien. Pet Store ha sido actualizado recientemente que se ajuste y se beheficie de la norma J2EE 1.3. Puede encontrar otros ejemplos adecuados en http://www-106.ibm.co~developeworks/ y en http:// developer.java.sun.comjdeveloper/.

Capitulo 23

Cornpetencia en el mercado de servidores de aplicacion


Diversas compafiias estin compitiendo en el espacio J2EE con sus productos de sewidor de aplicacibn. Existen varios niveIes de competencia. En el nivel superior, BEA WebLogic compite directamente con Websphere de IBM y, rnis recientemente, con las familias de servidores iPlanet de Sun-Netscape Alliance y el nuevo Oracle IAS. A menor escala, IBM y BEA compiten con SaphireIWeb de Bluestone/HewlettPackcard, SilverStream Application Server de SilverStream, GemStoneIJ de Gemstone Systems, Apptivity de Progress y Enterprise Application Server de Sybase. A continuaci6n, una lista de enlaces con rnis informaci6n:
0 ATGDynamo, http: //wai. atg. com/en/products/das. jhtml

0 Hewlett-PackardBluestone, http : //wai. bluestone. coml

0
O

GemStoneJJ de Gemstone Systems, http : / / w . gemstone. com/ IBMWebSphere, http: //wai-4. ibm.com/software/webservers/appserv/

Progress Apptivity, http: //www.progress com/apptivity/ SilverStream Application Server, http: / /silverstream. com/ IPlanet de Sun-Netscape Alliance, http : / / w . iplanet .com/products / iplanet-application/

0 0

ApplicationServerdeSybase, http: //wai. sybase . com/products/easerver/

La cuestion esti en q u t vendedor tiene el mejor producto para el proyecto establecido. Asi como qu6 producto se ajusta mejor a las habilidades del equipo de desarrollo y administradores del sistema. En 10s ultimos dos o tres afios, el mercado de servidores de aplicaci6n ha sido una carrera entre dos compafiias, BEA y IBM. Sin embargo, la carrera hoy en dia incluye a Oracle, Sun y Hewlett Packard entre otras. La mayoria del espacio se divide en la actualidad entre BEA y IBM, aunque hay una 14 empresas trabajando en productos de tiPo Servidor de Aplicaci6n y esta cifra ni siquiera incluye ofrecimientos de codigo abierto. C6digo abierto es el t6rmino aplicado a1 software habitualmente disponible de forma gratuita asi como tambitn lo esti su c6digo fuente. Este tipo de software sigue normalmente el modelo de licencia de http:// www.gnu.org/ o http://www.opensource.org/. Bisicamente, elto significa que esti obteniendo software gratuito con codigo abierto sin apoyo comercial. Tambikn pueden aplicarse otras restricciones. El codigo puede ser tan bueno o mejor t p e una alternativa comercial pero existe una linea de atenci6n en caso de haya algun problema. Apache es un buen ejemplo de paquete de software de codigo abierto. Es uno de 10s mejores servidores Web disponibles. Puede obtener el c6digo binario y el codigo fuente desde http:// www.apache.org/. En el espacio de servidor de aplicaci6n y el espacio de equipo de servlet hay algunas alternativas. Si s61o necesita un equipo Servlet, una de las opciones de c6digo abierto mis populares es Tomcat. Es gratis y se adapta hasta a JDK 1.3. JonAS es otra opci6n que rnis alli del equipo de servlet. Es compatible con EBJ 1.1 y cierta funcionalidad de EJB 2.0. JonAS es compatible con la ultima version JDK 1.3. Otra buena opci6n Jboss; va rnis alli de un equipo de servlet para ajustarse a EJB 1.2 y algunas funciones de 2.0.

Elegir una implementacion J2EE


Enhydra es otra implementacion de J2EE que sigue el enfoque de c6digo abierto, per0 sus autores parecen n o tener prisa e n lanzar nuevas versiones. La ultima vez que lo cornprobe todavia estaban trabajando e n una version comercial para u n o de sus patrocinadores. A continuaci6n, una lista de enlaces e n 10s que encontrari m i s information sobre servidores de aplicaci6n de cddigo abierto:
0

Enhydra,http://enhydr.a.enhydra.org/

0 JonAS,http://www.evidian.com/jonas/index.htm

0 Jboss,http://www.jboss.org/
0 Tomcat,http: / / j a k a r t a . a p a c h e . o r g / t o m c a t /

lmplementacionesJZEE
Las principales ireas e n la implementacion pueden variar de u n vendedor a otro, per0 existe cierta consistencia con las siguientes Preas de funcionalidad:

0 Servicios d e presentaci6n Habitualmente, 10s servidores de a ~ l i c a c i 6 n ofrecen contenido para la interfaz de usuario Y mantienen el estado sobre u n protocolo sin estado. Los servicios de presentaci6n se albergan en el contenedor Web. Algunos vendedores tienen implementaciones sencillas s61o para 10s servicios de presentacion, c o m o la edicidn sencilla de BEA WebLogic.
0

Servicios distribuidos d e objeto E n el nGcleo de 10s servidores Java e s t i la capacidad de ayudar a 10s componentes a comunicarse entre si. Los m6dulos de c6digo relacionado funcionalmente conforman u n componente. Las normas Java establecen como deben comunicarse 10s componentes (EJB). Servicios de transacci6n Muchos eventos generan mdtiples transacciones. P o r ejemplo, u n tipico pedido a una compafiia proveedora tiene que mermar el inventario, generar una factura, realizar una entrada de bienes por cobrar, marcar el pedido como completado y generar una notificacion de envio avanzada. Habitualmente, existen multiples pasos y ~ a n s a c c i o n e relacionadas s con un unico evento, que son comunicadas e n lote entre diferentes aplicaciones que se encargan de cada una de estas funciones. El retraso y falta de una proceso de dos fases introduce inconsistencias en las aplicaciones. Ademis, el retraso en el reflejo de estas transacciones desvirtua la concurrencia y fiabilidad de la informaci6n para aplicaciones de apoyo a decisiones. Los servicios de transacci6n coordinan estas transacciones relacionadas e n multiples sistemas y pueden actualizarlas casi en tiempo real simultaneamente. Servicios d e seguridad La seguridad distribuida es esencial para autentificar y garantizar el acceso a solicitudes de usuarios y aplicaciones de naturaleza distribuida.

0 Servicio d e disponibilidad Los servidores de a p l i c a c i h toman enfoques radicalmente diferentes para garantizar la fiabilidad e n caso de relevo, equilibrio de cargas y funciones de agrupamiento o clustering. La concesi6n es el rendimiento. C u a n t o mayor sea la calidad de 10s servicios integrados e n una aplicacion, mayor uso h a r i la aplicaci6n de las funciones q u e creen duplicaciones para seguridad de salvaguardia y mayor s e r i el efecto sobre el rendimiento del proceso. 0 Servicios d e directorio Estos servicios son utilizados p o r componentes para encontrar otros componentes. Java Naming Directory Interface (que se establece sobre LDAP) y Active Directory son las normas dominantes.

Capitulo 23
U

Reserva de conexiones a bases de datos U n servidor de aplicaci6n conecta con una base de datos y reserva las conexiones de forma que mbltiples usuarios puedan compartir de forma eficiente menos conexiones.

Si vamos rnis all5 y examinamos lo que deben apoyar 10s vendedores JZEE, encontraremos un conjunto de contratos de plataforma J2EE que deben cumplir el proveedor del producto J2EE. Existen cuatro contratos de plataforma que deben establecerse en cualquier servidor de aplicaci6n: A P I d e J2EE Definen el contrato entre 10s componentes de especificaci6n J2EE y la plataforma J2EE. El contrato especifica las interfaces de period0 de ejecucion y despliegue. El proveedor del producto J2EE debe implementar 10s API de J2EE de mod0 que se ajuste a la semintica y las politicas descritas en las especificaciones. El proveedor de componentes de aplicacion proporciona componentes que se ajustan a estos API y a estas politicas. Interfaces de proveedor de servicios (SPI) Los SPI definen el contrato entre la plataforma J2EE y 10s proveedores de servicios que puedan estar conectados a un producto J2EE. Los API Conector definen las interfaces de proveedor de servicios para integrar adaptadores de recursos con servidores de aplicacion J2EE. Los adaptadores de recursos son componentes J2EE que implementan la tecnologia de Conectores J2EE para un determinado sistema de informaci6n de empresa. El proveedor de producto J2EE debe implementar 10s SPI de J2EE de modo que se ajuste a la semintica y a las politicas descritas en estas especificaciones. U n distribuidor de componentes de proveedor de servicios debe asegurarse de que sus componentes se ajustan a estos SPI y a estas politicas.
E I

Protocolos de red Esta especificacion define la asociaci6n de componentes de aplicaci6n a protocolos de red estindar de industria. La asociaci6n permite el acceso cliente a 10s componentes de aplicacion desde sistemas que no han instalado tecnologia de productos J2EE. Esto permite una mejor inter~~erabilidad.

O Descriptores de irnplernentaci6n Como hemos visto en este libro, se utilizan para comunicar las necesidades de componentes de aplicaci6n a1 implementador. El descriptor de implernentacion es un contrato entre el proveedor o ensamblador de componentes de aplicaci6n y el implementador. Se requiere que el proveedor de componente de aplicaci6n proporcione una herramienta de implernentacion que interprete el descriptor de implernentacion J2EE y permita al implementador asociar 10s requisitos del componente de aplicaci6n a las capacidades de un producto J2EE y un entorno determinado.
Las principales ireas de implementaci6n y 10s cuatro contratos de plataforma estin presentes en cualquier producto de servidor de aplicaci6n certificado por J2EE. El mercado, sin embargo, no se centra solamente en un conjunto predefinido de servicios y contratos de plataforma. Los vendedores J2EE afiaden nuevos servicios y mejoras a sus productos para competir mejor en el mercado. Una vez implementada toda la especificacion J2EE y una vez optimizado el c6dig0,los vendedores toman diferentes enfoques para ahadir rnis valor a su producto. Pueden intentar daerenciar sus ofrecimientos afiadiendo rnis funciones que no se establecen como necesarias en la norma J2EE. Tambikn pueden mirar hacia futuras posibles tecnologias que pueden formar parte de la norma.

Funciones de valor anadido


Ademis de implementar las normas completas de J2EE, 10s vendedores pueden ampliar la funcionalidad del servidor para completar las tareas rnis complejas y permitir a sus productos formar parte de sistemas

Elegir una implernentacion J2EE


altamente heterogeneos. Elegir un servidor de aplicacion para un proyecto es casi como elegir un sistema operativo. Una vez comprometido y con el trabajo en funcionamiento, es dificil cambiar las instrucciones y empezar de nuevo con un nuevo producto. Asegurese de incluir un ingeniero de sistemas y uno de sus mejores arquitectos de software en el proceso de toma de decisiones.

Los desarrolladores deben tener como objetivo el uso de funciones estdndar y extensiones independientes del servidor de modo que su c6digo no esti ligado a un producto concreto. Si se escribe un EJB con funciones que s61o estin disponibles para un vendedor concreto, ese c6digo no podrd ejecutarse en un producto diferente.
Algunas de las ireas que analizaremos a continuation hacen referencia a posibles rutas de integracion con otros sistemas heterogeneos como implementaciones C O M y .NET; integracion con herramientas de desarrollo; mejoras en opciones de alta disponibilidad; apoyo para gesti6n de aplicaciones; apoyo para diferentes lenguajes; apoyo para diferentes sistemas operativos; integracion de funcionalidad de aplicacion adicional como personalizaci6n. Asimismo, existen implementaciones de normas futuras. Las ireas de expansion que estin explorando 10s vendedores son principalmente la conectividad con sistemas CORBA, C O M y .Net. En algunos productos 10s desarrolladores pueden envolver objetos C O M / C O M + como clases Java para utilizarlos con el servidor de aplicacion o envolver objetos Java y EJB con asociaciones C O M + para invocaciones por parte de aplicacion de Microsoft como Microsoft Internet Information Server, ISS u otros servicios en el sistema .NET. Esto puede ser bastante conveniente a la hora de construir un sistema que debe funcionar con sistemas ya existentes escritos para un entorno Microsoft. Tambien resulta beneficioso si se necesitan las transacciones integradas entre dos sistemas a traves de capacidades de transaction extendidas. La conectividad con CORBA facilita la integracion de sistemas de legado en una aplicacion. Para 10s desarrolladores, la integracion de J2EE con diferentes Entornos Integrados de Desarrollo (IDE) es esencial. Varios entornos de desarrollo Java, como WebGain Studio (un juego de herramientas Java basado en Visual Cafe), VisualAge de IBM, Borland Jbuilder y Forte para Java de Sun, son compatibles con la integracion en servidores de aplicacion. La operaci6n de agrupamiento o clustering puede extenderse mis alli del contenedor EJB para proporcionar el agrupamiento de piginas JSP y la sesi6n de usuario puede ser almacenada y replicada en una granja Web, que es un conjunto de equipos de servidor Web que responden a una solicitudes de navegador. Los vendedores de servidores de aplicacion J2EE definen un cluster como un grupo de equipos que funcionan juntos para proporcionar de forma transparente servicios de empresa. Dejan una definicidn vaga porque cada vendedor implementa la operacion deagrupamientode forma diferente. Se trata de una funcion deseable puesto especialmente para sitios Web de grandes dimensiones que implican a cientos de miles de transacciones por segundo. Podemos agrupar piginas Web y componentes en multiples servidores, asi como agrupar mdtiples servidores ejecutados en diferente hardware y diferentes sistemas operativos en una unica entidad de red. Los servidores agrupados deben todos estar localizados en el mismo LAN. La operacion de agrupamiento o clustering permite a un servidor replicar diferentes partes de una aplicaci6n en multiples equipos, proporcionando capacidad de relevo, equilibrio de cargas y reajustabilidad. IBM y BEA ofrecen operaciones de agrupamiento en multiples niveles dentro de una aplicacion, asi como agrupamientos de la misma plataforma del servidor. Sin embargo, lo que convierte en exclusiva a la linea de productos WebLogic es su compatibilidad con la agrupacion de piginas Web y componentes EJB. La agrupacion de piginas Web permite a WebLogic replicar la logica de aplicaci6n que crea respuestas para clientes Web, mientras que la operacion de agrupamiento de componentes posibilita la recuperacion total de EJB de sesi6n con estado y de entidad. Areas adicionales de competencia pueden incluir funciones como compatibilidad con Simple Network Management Protocol (SNMP), Wireless Markup Language (WML) y manejo XML, almacenamiento en cache perfeccionado de piginas, replicaci6n de objetos y sesiones de usuario, nuevas interfaces de auditoria y registro y filtrado de conexiones.

Capitulo 23
El equilibrio de cargas implementado a travis de manejadores IIOP, la operaci6nde agrupamiento de transacciones y el anilisis de carga de servidor pueden utilizar factorias de objetos (procesos que crean referencias de objetos) para influir en la localizaci6n de objetos individuales.

Implementation actual de normas futuras


O t r o tip0 de competencia generalizado es la implementaci6n de normas futuras antes de que se conviertan en normas. Esto tiene algunos riesgos asociados, tanto para el vendedor como para el desarrollador. Sin embargo, 10s grandes vendedores han reducido las entregas de continuaci6n para que las normas J2EE sean compatibles con nuevas normas aprobadas cuando se pongan a disposici6n del publico. La d t i m a actuahaci6n de las normas J2EE tambiin seriala un grupo de posibles directrices futuras que podrian ariadirse a las ultimas versiones de las normas J2EE, como: Servicios Web Es un tema muy candente que probablemente forme parte de las siguientes normas J2EE. Una serie de contribuciones ayudarin a la definici6n de servicios Web, incluido API para Mensajeria XML (JAXM), API Java para Registros XML (JAXR), API Java para XML-RCP, WAX-RCP) y definiciones para implementar servicios Web.
0

API de asociaci6n de datos XML U n XML cobra mis importancia en la industria, mis y mis aplicaciones de empresa necesitarin hacer uso de XML. Esta especificaci6n requiere apoyo bisico XMI SAX y D O M a travks del API JAXP, per0 muchas aplicaciones se beneficiarin de la tecnologia de asociaci6n de datos XML, mis ficil de utilizar. Protocolo de Arranque de Red Java (JNLP) TambiCn conocido como Java WebStar. El Protocolo de Arranque de Red Java define el mecanismo para la implementacion de aplicaciones Java en un servidor y el arranque desde un cliente. Futuras versiones de esta especificacion pueden requerir productos J2EE para poder implementar clientes de aplicaci6n de modo que puedan ser arrancados por un cliente JNLP y de rnodo que 10s contenedores de cliente de aplicaci6n puedan arrancar clientes de aplicacion implementados utilizando JNLP. SPI de J2EE Muchos de 10s API que conforman la plataforma J2EE inchyen una capa SPI que permite a 10s proveedores de servicios o a otros cornponentes de nivel de sistema estar conectados. Esta especificacidn n o describe el entorno de ejecucion para todos 10s proveedores de este servicio, ni 10s requisitos de empaquetado e implementaci6n pam todos 10s proveedores de servicios. La arquitectura de Conectores J2EE define 10s requisitos para ciertos tipos de proveedores de servicios llamados adaptadores de recursos. Futuras versiones de esta especificaci6n definirin de forman rnis exhaustiva estos SPI J2EE. RowSet J D B C Proporcionar un mod0 estindar de enviar datos tabulares entre 10s componentes remotos de una aplicaci6n distribuida de empresa. API de seguridad El objetivo de la plataforma J2EE es separar la seguridad de la Iogica de empresa, proporcionando controles declarativos de seguridad para componentes de aplicaci6n. Algunas aplicaciones, sin embargo, necesitan mis control sobre la seguridad del que puede ofrecer este enfoque. Futuras versiones de esta especificaci6n pueden incluir API adicionales. API de implementaci6n Las herramientas de implementacion siguen la norma de API de Despliegue para permitir el funcionamiento con todos 10s productos J2EE.

Elegir una implernentacion J2EE


u API de gesti6n
Las aplicaciones J2EE y 10s productos J2EE deben ser gestionables. Futuras versiones de esta especificacion incluiran API para apoyar funciones de gesti6n. U n sencillo ejemplo es la noci6n de consola de gestion centralizada para iniciar y detener todos 10s servicios J2EE relacionados.
0

SQLJ parte 0 Apoya la integraci6n de instrucciones SQL en programas escritos en el lenguaje de programacion Java. Un cornpilador traduce el programa en otro programa que utiliza un period0 de ejecuci6n SQLJ. Las clases de periodo de ejecucidn SQLJ pueden empaquetarse con una aplicaci6n J2EE que utilice SQLJ, permitiendo que esa apkaci6n se ejecute en cualquier plataforma J2EE.

Los Gltimos y mas exhaustivos avances en relacion a1 futuro rumbo de las normas J2EE puede encontrarlos en http://java.sun.com/j2ee/.

Posibles caminos potenciales para funciones de valor anadido


Con el paso del tiempo, 10s servidores de aplicaci6n ascienden en la cadena alimentaria del software, ahadiendo cada vez mis funcionalidad (anteriormente localizada en aplicaciones y servicios especializados). Otras ireas de expansi6n de contorno por parte de 10s vendedores de servidores de aplicaci6n son las siguientes:

o Capacidades de portal
Una vista consolidada de las piginas Web que son personalizadas para una determinada clase de usuario (por ejemplo, comprador, empleado, proveedor, portales socios). Los portales se estin extendiendo como un mod0 de conectar con todos 10s sistemas de una empresa, al ofrecer una diversa gama de apartados en un sitio; a menudo, apartados y servicios tornados de otros sitios. Algunos de 10s grandes vendedores ya ofrecen capacidades de portal son sus productos, como IBM Portal Server, BEA Portal Server y iPlanet Portal Server. N o existe realmente un conjunto de especificaciones de portal, per0 puede encontrar lo que se conoce como API Portlet, desarrollado por el grupo Apache. Se trata de un enfoque de bajo nivel para desarrollar API para apoyar la funcionalidad mis comdn de tip0 portal.
0

Flujo de trabajo Todas las funciones para enfrentarse a un proceso completo de empresa en una gran empresa rara vez estin contenidas en una Gnica aplicaci6n o sistema. Consecuentemente, 10s usuarios necesitan un mod0 de automatizar el flujo del proceso, incluida la interaccion manual con usuarios, en mGltiples ireas de la aplicaci6n. Por ejemplo, dn pedido en la Web puede ser entregado a sistema de entrada de pedidos del departamento de Planificaci6n de Recursos de la Empresa ( E m ) y, a su vez, algunos componentes de este pedido pueden pasarse a un proveedor o a un socio. Esto tambikn puede tener lugar en paralelo con mGltiples pasos entre departamentos y cornpahias. Personalizaci6n El uso y 10s perfiles del sitio son registrados para usuarios individuales y el contenido presentado es personalizado segGn sus intereses. Gesti6n de contenido Almacena etiquetas; indexa, asegura y recupera contenido como documentos e imigenes que deben ser presentadas en piginas Web. TambiCn es necesario gestionar todo tip0 de contenido, tanto en sistema de archivos como en la base de datos. Cualquier cosa, desde una imagen, una fila de datos o un archivo general, hasta un soporte de corriente, puede ser clasificada como contenido para ser gestionado. Integraci6n Una plataforma de integraci6n para aplicaciones, que funciona sobre EAI (Integraci6n de Aplicaci6n de Empresa. La Arquitectura de Conectores Java UCA) se esti haciendo muy popular

Caoitulo 23
en el rnercado. Los vendedores de sisternas de inforrnaci6n de ernpresa pueden seguir las especificaciones JCA y ofrecer adaptadores de recursos estindar para sus productos. Estos adaptadores pueden conectarse a un servidor de aplicaci6n y proporcionar integraci6n y conectividad entre el EIS y el servidor de aplicaci6n. Puede, por ejemplo, integrar un sistema Oracle con Siebel y rnuchos otros productos. Si desea una lista cornpleta de conectores disponibles en el rnercado, visite http://java.sun.com/j2ee/connector/products.htrnl. Esta lista esti en constante

actualization.
0

Almacenamiento en cachi Ticnicas de rnejora del rendirniento que se basan en replicas de contenido, datos y aplicaciones para elirninar 10s ernbotellamientos de rendirniento en la red. El alrnacenarniento en cache puede funcionar en diferentes niveles, desde sisternas de archivos y sistemas RDBMS, hasta instanciaci6n de objetos, actividades de servidor Web, actividades de autentificacihn y trifico de red. Provisi6n de derechos de usuario y servicios de administraci6n N o s610 tenernos que crear y desplegar aplicaciones JZEE, tarnbien tenemos que gestionarlas en el tiernpo y arnpliarlas y rnejorar su funcionalidad existente. La necesidad de herrarnientas de ficil uso para gesti6n y control del sisterna es un irea clave de futuras norrnas J2EE.

La cornpetencia en el rnercado puede contribuir a aportar rnejores productos y precios rnis bajos, pero tambien puede crear cierto nivel de confusi6n. En la siguiente s e c c h , revisarernos el conjunto de parirnetros que debernos considerar a la hora de elegir una irnplernentaci6n J2EE.

Parametros de evaluacion
La plataforrna Java proporciona un entorno rnuy abierto para que 10s vendedores cornpitan. El conjunto de productos J2EE disponible en el mercado se ha incrernentado hasta alcanzar grandes cifras y son muchos lo que prevkn que estas cifras seguirin aurnentando. Varios vendedores ya implernentan el grupo completo de especificaciones J2EE y otros grupos ampliados de funcionalidad. Tornar una decisi6n definitiva puede convertirse en un ejercicio de cornparaci6n entre funcionalidad, nivel de fidelidad en las especificaciones, filtirna irnplernentaci6n de especificaciones, precio, cornpatibilidad y adopci6n de ernpresa. En la siguiente tabla, enurnerarnos algunos articulos para cornparar a1 elegir su servidor de Aplicaci6n. Los ejernplos se rnuestran utilizando a 10s tres principales vendedores del rn~rcado de hoy en dia: BEA, IBM y Oracle. Algunas cifras pueden haber carnbiado cuando lea estas listas per0 probablemente podri utilizarlas corno referencia para ireas en las que cornparar vendedores J2EE: N o intente utilizar 10s datos de esta tabla para comparar estos productos; se trata simplemente de una guia para completar su informaci6n.

Vendedores Precio rnedio por procesador Producto de la ernpresa Alrnacena en cache C1Gsterizaci6n Reserva de conexiones

BEA WebLogic 8.60K(aprox.) 14.65K(aprox.) Si Si Si

IBM Websphere 6.90K(aprox.) 30.15K(aprox.) No Si Si

Oracle IAS 8.60K(aprox.) 17.25K(aprox.) Si Si Si

I
I

Elegir una implementacion J2EE


Vendedores Compatible EJB Relevo Compatible JSP Compatible LDAP Equilibrio de cargas Servicios de portal Compatible con servlet SAX XML BEA WebLogic 2.0 Si 1.2 Si Si Si 2.3 2.0

IBM Websphere
1.2 Si 1.1 Si Si Si 2.2

Oracle IAS 2.0 Si 1.1 Si Si Si 2.3 1.0

1.O

Si esta' interesado en cifras actualizadas, consulte 10s sitios W e b del vendedor de estos productos.
Es muy importante saber la compatibilidad de una implementacion JZEE. U n vendedor puede incluir ciertas funciones de las ultimas e ~ ~ e c i f i c a c i o nJ2EE e s en un area de su producto y vender ese producto hasta actualizar las otras ireas. Si. realmente sucede. C o n frecuencia hav ocasiones en las aue 10s vendedores etiquetarin el producto para que se ajuste a J2EE 1.x y tengan un mapa en el que indiquen cuindo realmente todos 10s componentes estarin al mismo nivel J2EE. Dependiendo del proyecto futuro, podremos utilizar un producto que tenga diferentes niveles de compatibilidad para diferentes servicios. Esto puede convertirse en ocasiones en un problems durante la instalaci6n y la configuraci611, y tambiin puede crearlo con relaci6n a 10s requisites J D K para sus sisternas. A continuaci6n, mostramos una tabla de referencia ripida para las dos ultimas entregas J2EE. Esta tabla puede ayudarle durante la fase de anilisis antes de comprometerse con un determinado vendedor. Tambikn puede ayudarle durante la revisi6n de sus sistemas existentes para asegurarse de que su servidor de aplicaci6n es la mejor combinaci6n posible:

XML

Analizador JAXP 1.1 XML

0 ,No requiere analizador XML 0 N o ~ u e d editar e vista XML de una

0 Vista XML de editable JSP

JSP

o Paginas JSP pueden editar


salida XML
0

O Piginas JSP pueden editar salida

XML

Filtros de servlet fitiles para salida XML salida XML

o N o hay filtros disponibles


0 Servlets pueden generarsalidaXML

0 Servlets pueden generar


0

Descriptores EJB en XML Implementaci6n JMS 1.0 requerida Conector J2EE 1.0

U Descriptores EJB en XML


0

JMS (Java Message Service) J C A (Java Connector Architecture)

0 0

Implernentaci6n JMS optional

0 Conectores J2EE n o disponibles

Capitulo 23

Enterprise JavaBeans 2.0

Beans controlados por rnensaje Interoperabilidad requerida Persistencia gestionada por contenedor mejorada Lenguaje de consultas EJB (EJB QL) Interfaces locales

O O

Ningbn modelo EJB para comunicaci6n asincrona Primera entrega con persistencia gestionada por contenedor datos gestionados por contenedor

o N o hay lenguaje de consultas para

RMI-IIOP

Interoperabilidad requerida Requisitos de especificaci6n O M G actualizados

o N o se requiere inter~~erabilidad
0 Requisitos I I O P no alineados

e~~ecificamente con O M G
0 JavaMail 1.1

Java Mail JAF (JavaBeans Activation Framework) JTA (Java Transaction API) JDBC J2SE Servlet

JaGaMail 1.2 N i n g h cambio en requisitos JAF Ning6n cambio en requisitos JTA Ningfin cambio en requisitos JDBC J2SE 1.3 o posterior Servlet 2.3 Filtros (nuevo ti ode componente

0 JavaBeans Activation Framework 1.0 (JAF)


O

JTA 1.0

0 Paquete opcional JDBC 2.0 0 J2SE 1.2 o posterior 0 Servlet 2.2

el)

Eventos de aplicaci6n (princi a1 uso para gestidn de ciclo de vida la a licaci6n y para comunicar el estado $obal de la aplicacih a las sesiones) Compatible con sesiones de aplicaci6n en migracion en configuraciones de servidor distribuido o clusterizado Validaci6n del periodo de instalaci6n de dependencias de bibliotecaRoles "Ejecutar como" para permitir a 10s Servlets utilizar EJB que requieren autentificacion Mayor control sobre codificacion de caracteres para localizaci6n de salida de aplicaci6n

Elegir una implernentacion J2EE

JSP (JavaServer Pages)

0 JSP 1.2
0 0

0 JSP 1.1

Vista XML de pigina JSP Validadores de eriodo de traduccion definidos por e desarrollador para piginas JSP

Cambios incrementativos para simplificar el desarrollo

Mejor rendimiento

o Ofrece mejor portabilidad

En la actualidad, existe una tendencia por la que 10s vendedores estin agrupando en lotes sus productos con sistemas operativos. Sun agruparin en lotes iPlanet Applicaction Server con Solaris. Sun podria ser una tienda linica de servicids proporcionando tanto productos hardware como software. La futura estrategia de Sun de agrupamiento por lotes es evidente en la actualidad: el vendedor ya incluye una copia de evaluation gratis de con servidor de aplicacion iPlanet con Solaris. H P agrupari Bluestone con HP-UX. H P adquiri6 el vendedor de servidor de aplicaci6n Bluestones el aiio pasado por m6s de 860 millones de euros cuando todavia estaba revendiendo BEA WebLogic. H P compite en mirgenes de hardware con IBM y Sun, por lo que claramente necesitaba su propio servidor de aplicacion adaptado para ejecutar en HP-UX. Lo que deben hacer estos vendedores de infraestructuras precargar sus servidores de aplicacion en su hardware con el sistema operativo. El servidor de aplicacion es una extension logica del sistema operativo. Proporcionar un conjunto de servicios como equilibria de cargas, mensajeria y tolerancia de fallos que permite a 10s desarrolladores centrarse en el desarrollo de la aplicacion. Las compaiiias que obtienen su servidor de aplicacion y su sistema operativo de un h i c o vendedor se beneficiarin de un ficil desarrollo y una sencilla administraci6n. Instalar un servidor de aplicacion e implementar aplicaciones bien requiere asesores con experiencia, desarrolladores e ~ ~ e r i m e n t a d opersonal s, de T I cualificado y apoyo del vendedor. En pocas palabras, se precisa talento, tiempo y dinero. Estos factores representan una curva de aprendizaje que las organizaciones necesitan superar. Se requiere un nuevo estilo de programacion y nuevas habilidades de IT. A continuacion, revisaremos algunos de 10s aspectos cambiantes que surgen cuando la tecnologia J2EE llega a organizaciones que no la conocen.

Comunidad de desarrollo
Merece la pena analizar las diferentes comunidades de desarrollo formadas alrededor de ciertos vendedores J2EE. Si el proyecto va a requerir un largo ciclo de desarrollo, podria haber varias incognitas debido a la naturaleza del proyecto y a1 entorno final de implementacion. La presencia de una fuerte comunidad de desarrollo es muy importante. Una compaiiia quizis no tenga gran apoyo disponible para sus ingenieros y personal de IT. Esto podria traducirse en reducidos niveles de apoyo del vendedor mis alli de las opciones tradicionales. Algunos vendedores proporcionan recursos on-line para desarrolladores como punto de partida. Estas comunidades pueden expandine mis all6 del esfuerzo inicial del vendedor. Estos son algunos de 10s sitios Web dedicados a desarrolladores creados por diferentes vendedores y grupos de codigo abierto:

O
O

BEAhttp://developer.bea.com/index.jsp IBMhttp://www-16.ibm.com/developerworks/

IPlanet h t t p : / / d e v e l o p e r . i p l a n e t .corn/

O Jboss http://www.jboss.org/lists.jsp O

Oracle h t t p : / / o t n . o r a c l e . c o m / i n d e x . h t m l

Los grupos electronicos de noticias son tarnbikn un recurso excelente para que 10s desarrolladores puedan obtener mis informaci6n y apoyo sobre diferentes productos. Para una lista exhaustiva de grupos de noticias, puede consultar http://groups.google.corn/.

Resumen
J2EE es una norma en evoluci6n que serl actualizada en el futuro para proporcionar rn6s funcionalidad y mejores servicios para aplicaciones de empresa de base Java. Los servidores de aplicaci6n son la principal representaci6n de productos para especificaciones J2EE; proporcionan contenedores Web y contenedores EJB que resultan claves para cualquier aplicacion JZEE. Existen varios productos cornerciales disponibles hoy en dia en el mercado, asi corno muy buenas alternativas de codigo abierto. Dependiendo del proyecto o de las tareas concretas, tendremos que investigar un poco para encontrar la mejor opci6n para nuestro trabajo. Los vendedores de servidor de aplicaci6n no implementan solarnente las e~~ecificaciones J2EE; normalrnente dan un paso rnis y ofrecen funciones de valor afiadido para diferenciar sus ofertas. Esto significa que existe una curva de aprendizaje asociada a1 uso de servidores de aplicacion. Las opciones de aprendizaje y una buena comunidad de desarrollo son la clave para un proyecto de kxito. Recuerdelo durante cualquier proceso de decisi6n de tecnologia. Finalrnente, el hardware y la arquitectura de sistemas son tarnbikn muy importantes a la hora de decidir quP servidor de aplicacion es rnis adecuado para un deterrninado proyecto. En el siguiente capitulo, analizaremos el ernpaquetado e implernentaci6n de nuestras aplicaciones J2EE.

Empaquetado e implernentacion JZEE


La especificaci6n J2EE comprende distintas sub-especificaciones funcionales. Sin embargo, no siempre resulta obvio c6mo deben organizarse para formar una aplicaci6n J2EE completa. La especificaci6n J2EE proporciona directrices para la estructuraci6n y creaci6n de aplicaciones J2EE, una de las cuales esti relacionada con el empaquetado. Las especificaciones individuales proporcionan directrices para el empaquetado de componentes individuales como EJB, piginas JSP y servlets. En este capitulo analizaremos el mecanismo de empaquetado. N o trataremos c6mo construir EJB, aplicaciones Web o ficheros de archivos de adaptador de recursos, aspectos analizados en distintos capitulos. En su lugar, nos centraremos en las relaciones de 10s componentes con un archivo EAR y en el proceso de construcci6n de archivos EAR. Algunas de las cuestiones que plantearemos son las siguientes:
0

iCuiles son las reglas de uso del empaquetado J2EE en oposici6n a1 empaquetado de componentes? iQuk puede entrar en un paquete J?EE? iEs necesario el empaquetado J2EE; su utilization provoca cambios de comportamiento?

0 0

A1 responder estas preguntas aprenderemos:


0 0 0

C6mo funcionan 10s esquemas de carga de clases J2EE C 6 m o crear archivos Enterprise Archives (EAR) C6mo tratar la dependencia y las clases de utilidad

Capitulo 24

Analisis del empaquetado JZEE


Una aplicaci6n J2EE se compone de:
0 0

U n o o mis componentes J2EE U n descriptor de implementaci6n de aplicaci6n J2EE

Cuando uno o mis componentes heterogkneos necesitan utilizarse entre si debe crearse, una aplicacion J2EE. Hay ciertas consideraciones a tener en cuenta a la hora de construir una aplicaci6n J2EE, incluido:
0

Los tipos de componentes J2EE que pueden ser empaquetados en una aplicacidn J2EE Las funciones de 10s individuos que intervienen en la creacion de paquetes J2EE Las limitaciones actuales del empaquetado J2EE Los enfoques de carga de clases que utilizan diferentes vendedores para cubrir las necesidades de interacciones de componentes J2EE

0
0 0

lQue elementos pueden ser empaquetados?


La especificaci6n J2EE diferencia entre recursos que se ejecutan en un contenedor y recursos que pueden ser empaquetados en un archivo J2EE de aplicacion de empresa, Enterprise Application ARchive (EAR). U n archivo EAR se utiliza para empaquetar u n o o m6s mddulos JZEE en u n dnico mddulo de modo que puedan carga de clases e implementaci6 en u n servidor.

J2EE aclara la diferencia entre contenedores de periodo de ejecucion y modulos de implementaci6n. Los contenedores de periodo de ejecucion son interceptores de nivel de solicitud que proporcionan servicios de infraestructura alrededor de componentes del sistema. U n m6dulo de implementaci6n es una estructura de empaquetado para componentes que se ejecutarin en ultimo lugar en un contenedor de periodo de ejecucion. Recuerde la estructura de 10s contenedores J2EE:

Empaquetado e implernentacion J2EE

Contenedor de Applet
-

Applet HTTP SSL


A
I I

Contenedor Web
C

Contenedor EJB

--+

JSP

Servlet

Base de Datos

Contenedor Cl~ente de Apl1cac16n Chente de Apl~cac~on

HTrP SSL

O El contenedor EJB El contenedor EJB proporciona recepticulo e interceptaci6n en el nivel de solicitud para 16gica de ernpresa. El contenedor EJB permite a 10s JEB tener acceso a JMS, JAAS, JTA, JavaMail (que utiliza JFA), JAXP, JDBC y la arquitectura de conectores.

El contenedor Web El contenedor Web proporciona interceptaci6n para solicitudes enviadas en HTTP, FTP, SMTP y otros protocolos. La mayoria de 10s contenedores Web s61o son compatibles con HTTP(S), per0 podrian serlo con una variedad rnls arnplia de protocolos si asi lo decidieran. El contenedor de aplicaci6n Web perrnite a piginas JSP y a servlets tener acceso a 10s rnismos recursos que proporciona el contenedor EJB.
/

O El contenedor cliente de aplicaci6n U n contenedor cliente de aplicaci6n proporciona interceptaci6n de nivel de solicitud para aplicaciones Java independientes. Estas aplicaciones se ejecutan de forrna rernota, en una JVM diferentes de aquilla en la que opera el contenedor Web y el contenedor EJB.
U n programa ejecutado en un contenedor cliente de aplicaci6n es muy similar a un prograrna Java con un metodo m a i n ( ) . Sin embargo, en lugar de que la aplicaci6n estC controlada por una JVM, un envoltorio controla el prograrna. Este envoltorio es el contenedor.cliente de aplicaci6n. Los contenedores cliente de aplicaci6n son un nuevo concept0 de la especificaci6n J2EE y deben ser facilitados por su proveedor de servidor de aplicaci6n. U n contenedor cliente de aplicaci6n puede optirnizar el acceso a un contenedor Web y a un contenedor EJB a travCs de autentificaci6n directa, ejecutando equilibrio de cargas, permitiendo

Capitulo 24
rutinas de relevo, proporcionando acceso a variables de entorno de lado senidor y propagando adecuadamente contextos de transaction. Los programas que se ejecutan dentro de un contenedor cliente de aplicaci6n tienen acceso a recursos JAXP, JDBC, JMS y JAAS en un senidor de aplicacidn remoto.

o El contenedor de applet
U n contenedor de applet es un tip0 especial de contenedor que proporciona interceptaci6n en el nivel de la solicitud para programas Java ejecutados en un navegador. U n punto importante que debe recordar es que un contenedor de applet no proporciona acceso a ningiin recurso adicional como JDBC o JMS. Los applets ejecutados en un contenedor de applet deben presentar solicitudes de recursos directamente a un senidor de aplicaci6n (en lugar de realizar una solicitud a1 contenedor y dejar que el contenedor la presente a1 senidor de aplicacion). La especificacion EJB no establece ninguna regulaci6n sobre cdmo un applet debe comunicar con un contenedor EJB, per0 la especificaci6n J2EE si. La especificaci6n J2EE requiere que 10s applets que quieren utilizar directamente un EJB deben utilizar el protocolo HTTP(S) y tunelizar las invocaciones RMI. Muchos vendedores de senidores de aplicaci6n apoyan una forma de tunelizaci6n HTTP para permitir esta operaci6n. Los componentes que pueden ser empaquetados en un archivo EAR J2EE no se correlacionan directamente con estos componentes que contienen 10s contenedores. N o existen requisitos bisicos en cuanto a lo que debe incluirse como minimo en un archivo EAR. U n archivo EAR esti compuesto de cualquier cantidad de 10s siguientes componentes:
0

Archivos JAR de aplicaci6n EJB U n archivo JAR de aplicaci6n EJB contiene uno o mis EJB. Archivos W A R de aplicaci6n Web U n archivo WAR contiene una iinica aplicacion Web. Puesto que un archivo EAR contiene mliltiples aplicaciones Web, cada aplicaci6n Web de un archivo EAR debe tener un context0 de implementaci6n exclusive. El mecanismo de despliegue para archivos EAR s61o permite esta especificacion de diferentes contextos. Archivos J A R de cliente de aplicaci6n El archivo-JAR de cliente de aplicacion contiene una linica aplicacidn independiente Java que esti destinada a ejecutarse en una contenedor cliente de aplicaci6n. El archivo JAR de cliente de apkaci6n contiene un descriptor de implementation especializado y esti compuesto de un mod0 similar a un archivo JAR EJB. El archivo JAR contiene las clases requeridas para ejecutar el cliente independiente, ademis de las librerias de cliente necesarias para acceder a JDBC, JMS, JAXP, JAAS o a un cliente EJB. Archivos R A R de adaptador de recursos Archivo RAR de adaptador de recursos contiene clases Java y librerias nativas requeridas para implementar un adaptador de recursos de Arquitectura de Conectores Java (JCA) a un sistema de informaci6n de empresa. Los adaptadores de recursos no se ejecutan en un contenedor. En cambio, son disefiados para ser ejecutados como puente entre un servidor de aplicaci6n y un sistema externo de informacidn de empresa.

Cada uno de estos componentes es desarrollado y empaquetado individualmente aparte del archivo EAR J2EE y su propio descriptor de implementation. Un archivo EAR J2EE es una combinaci6n de uno o mis de estos componentes en un paquete unificado con un descriptor de implementaci6n personalizado.

Capitulo 24
Aunque son empaquetadas como parte de un archivo EAR J2EE, no operan dentro del contexto de un contenedor J2EE. Por lo tanto, puesto que 10s archivos de adaptadores de recursos no tienen un contenedor JZEE, no necesitan tener un implementador J2EE implicado en su activation. Los programas de cliente de aplicaci6n operan dentro del contexto de un contenedor J2EE per0 no son implementados en un senidor de apkaci6n. Los programas de cliente de apkaci6n se ejecutan de forma independiente y el implementador no es responsable de configurar el entorno del contenedor para estos programas. El implementador produce aplicaciones Web listas para contenedor, aplicaciones EJB, applets y clientes de aplicaci6n personalizados para el entorno de destino del senidor de la aplicaci6n. Administrador del sistema El administrador del sistema es responsable de la configuration del entorno de red y operativo en 10s que se ejecutan 10s senidores de aplicaci6n y las aplicaciones J2EE. El administrador del sistema tambien es responsable del control y el mantenimiento de las aplicaciones J2EE. En este capitulo, durante el anilisis de la creacion de archivos EAR y la resoluci6n de conflictos, de~em~efiaremos 10s roles de ensamblador e implementador de aplicacion.

Las limitaciones del empaquetado


Los archivos EAR cumplen 10s requisitos bisicos para empaquetar una aplicaci6n puesto que la mayor parte de las aplicaciones J2EE de base Web estin compuestas unicamente por aplicaciones Web y EJB. Sin embargo, 10s archivos EAR carecen de la capacidad de empaquetar complicadas aplicaciones JZEE. Por ejemplo, 10s siguientes componentes no pueden ser declarados en un archivo EAR, per0 con frecuencia son utilizados en una aplicacion J2EE:
0 Objetos J D B C ~ a t a s o u r c e 0 Objetos J M S ~ o n n e c t i o n ~ a c t o r y y ~ e s t i n a t i o n
O Mbeans JMX O

A l p n o s consumidores JMS que se ejecutan en una senidor de aplicaci6n como MessageConsumer queseejecutacomopartedeuna~erver~ession Clases que se desencadenan cuando una aplicaci6n se implementa o "desimplementa". (Estas clases son extensiones de propiedad proporcionadas por vendedores no definidos en la especificacion J2EE. Sin embargo, todos 10s vendedores las facilitan generalmente.)

En la actualidad, estos componentes tienen que ser configurados manualmente y desplegados a traves de una interfaz provista por el vendedor de la implementaci6n y son responsabilidad del administrador del sistema. Con el tiempo, el uso de estos articulos aumentari y, consecuentemente, seri muy importante que 10s archivos EAR se ajusten a1 empaquetado de estos componentes de modo que sea posible la portabilidad de la aplicaci6n.

Comprender 10s esquemas de carga de clases


En el period0 de ejecuci6n, cuando una clase es referenciada, necesita ser cargada por el Equipo Virtual Java. La JVM utiliza una estructura estindar de carga de clases para cargar clases en memoria. U n cargador

Empaquetado e implernentacion J2EE


de clases es una clase Java responsable de cargar clases Java desde una fuente. Las clases Java pueden ser cargadas desde un disco, un socket o cualquier otro medio; residen en cualquier parte. Los cargadores de clases son jerirquicos en el sentido en que pueden encadenarse en una relaci6n principal-secundario. Las clases cargadas por un cargador de clase secundaria tiene visibilidad (pueden utilizar) clases cargadas por cualquiera de 10s cargadores de clase principal. Las clases cargadas por un cargador de clase principal no tienen visibilidad para clases cargadas por cualquiera de sus cargadores de clase de sus secundarias. Los cargadores de clase y 10s archivos EAR son importantes puesto que 10s vendedores de aplicaci6n pueden desplegar m6dulos de aplicaci6n utilizando cargadores de clases comunes o diferentes. Si, dentro de una aplicaci6n, una aplicaci6n Web necesita acceder a un EJB, la aplicaci6n Web necesitari poder cargar aquellas clases que requiere. Debido a esta dependencia implicita entre diferentes m6dulos, 10s vendedores de servidor de aplicaci6n deben considerar diferentes enfoques para la estructuraci6n de cargadores de clases EAR de modo que se resuelvan estas dependencias. Una aplicaci6n independiente se implementa en su propio cargador de clase. Esto significa que si implementa un archivo de aplicaci6n Web y un archivo de aplicaci6n EJB por separado, las clases respectivas de cada aplicaci6n serin cargadas en diferentes cargadores de clases secundarias entre si. Las clases del cargador de clases de la aplicacion Web no resultarin visibles para clases cargadas por otros cargadores de clases. Esto supone un problema para las aplicaciones Web que quieren utilizar EJB que han sido implementados por separado. Antes de la aparicion de 10s archivos EAR, muchos desarrolladores implementarian un EJB y despuks volverian a empaquetar el mismo archivo JAR EJB como parte del directorio WEB- I N F \ l i b de la aplicacidn Web. Los mismos archivos de clase existirian en dos sitios diferentes de modo que la aplicaci6n completa pudiera funcionar correctamente, una situaci6n que debe evitarse. Las aplicaciones EAR se introdujeron para resolver este problema. Los archivos EAR n o s610 son un formato de empaquetado conveniente; tambikn proporcionan un esquema especial de carga de clases que permite a las aplicaciones de un archivo EAR acceder a clases de otras aplicaciones. La especificaci6n J2EE 1.3 no establece ningfin requisito especifico sobre c6mo debe funcionar un cargador de clases EAR. Concede a 10s vendedores de servidores de aplicaci6n flexibilidad a la hora de decidir c6mo deben ser cargadas las clases. Antes de implementar un cargador de clases EAR, un vendedor necesita decidir las siguientes cuestiones:
0

iSerin cargadas todas las clases de todas las aplicaciones del archivo EAR por un Cnico cargador de clases o diferentes cargadores de clases cargarin archivos separados? iDebe haber alguna relaci6n de cargadores de clase principal-secundaria entre diferentes aplicaciones del archivo EAR? Por ejemplo, si dos aplicaciones EJB dependen de l o g 4 j j a r , idebe mantenerse la visibilidad apropiada cargando l o g 4 j . j a r en un cargador de clase principal y cargando las aplicaciones EJB en una cargador de clase secundaria?

Si se crea una jerarquia de cargadores de clase, ihasta quk profundidad se permitiri la extensi6n de la jerarquia? Los EJB tienen relaciones inherentes entre si per0 las aplicaciones Web, no. Por lo tanto, ise cargarin las aplicaciones EJB de forma diferente a las aplicaciones Web de modo que pueda mantenerse la integridad de la aplicaci6n Web?

La opcion anterior a EJB 2.0


C o n anterioridad a1 Borrador 2 Final Pfiblico de EJB 2.0,los vendedores tenian mucha flexibilidad a la hora de elegir c6mo configurar un esquema de carga de clases. Las piginas JSP y servlets que necesitaban hacer uso de un EJB s610 precisaban poder cargar la interfaz inicial, la interfaz remota, 1as clases comunes y las clases de stub del EJB. Las clases comunes como excepciones y parimetros debian ubicarse en una

archivo JAR de dependencia y ser cargadas como un paquete de dependencia. Esta configuraci6n requiere que 10s vendedores determinen el modo que una aplicacion Web depende de un EJB para cargar la interfaz inicial, la interfaz remota y 10s stubs. U n vendedor podria implementar este sencillo esquema de carga de clases:
Cargador de C l a s s EAR

lnterfaz exportada a cargador de clases

-----

- - .-I

..I

. . . . . . . . . . . . . . . . . .

Cada EAR obt~ene su propla ~nstancla


I

I Llbrerias de dependencla y adaptador

.-

de recursos cargados aqul

v
Cag
Cagada de Clxes WebN

Cargador de Clases D B

WAR obt~ene su prop cargador de clases

WAR obt~ene su proplo cargador de clases

j j

Las llbrerias de dependencla espec~f~cadas por un WEB-INFWb especiflco son cargadas aqui para estar a~sladas

La carga d e clase d e apficacidn cliente n o esta' incluida e72 este modelo puesto que una apficacidn cliente se ejecutard en otro equipo virtual y estara' aislada d e todos 10s denza's componentes.

En este modelo, cada aplicaci6n EAR seria cargada por una instancia de cargador de clases EAR personalizada. Las aplicaciones EJB y las aplicaciones Web serian cargadas, cada una de ellas, por cargadores de clase descendientes del cargador de clase EAR. Cualquier archivo de clase que deba ser cornpartido por mis de una aplicacion del EAR seri cargado por el cargador de clase EAR. (Esto incluye cualquier biblioteca de dependencia comun y archivos de adaptadores de recursos.) Cualquier archivo cargado en el nivel de cargador de clases EAR es automiticamente visible a todas las clases cargadas por cargadores de clase. Todas las aplicaciones EJB son cargadas por un unico cargador de clases EJB que es descendiente del cargador de clase EAR. Incluso si tiene diferentes archivos JAR EJB, serin todos cargados por el mismo cargador de clases. Esto es asi para facilitar las llamadas entre EJB en diferentes aplicaciones albergadas en la misma JVM. Cada aplicacion Web es cargada en un cargador de clase diferente para mantener el aislamiento de clases. Por ejemplo, si cada aplicacion Web contiene un archivo llamado i n d e x . j s p , ese servlet creado a partir de la pigina JSP podria tener el mismo nombre de clases que 10s servlets equivalentes de otras aplicaciones Web. Cada aplicacion Web necesita la capacidad de cargar su propia version de ese servlet, por lo que cada aplicaci6n Web debe estar aislada en su propio cargador de clase. Para que las aplicaciones Web hagan uso de 10s EJB desplegados en el mismo archivo EAR, es necesario que las aplicaciones Web tengan visibilidad de las interfaces externas y las clases de implementaci6n de stubs de estos EJB. Puesto que 10s cargadores de clase de aplicaci6n EJB y Web son hermanos, las aplicaciones Web no tienen visibilidad directa de 10s archivos de clase correctos. El cargador de clase de apkaci6n Web y el cargador de clase de aplicaci6n EJB tienen, sin embargo, el mismo cargador de clase padre. Para permitir que la aplicacion Web pueda utilizar 10s archivos de clase del EJB, el cargador de clase de EJB puede tomar todas las interfaces publicas de cada EJB y sus archivos de implementacirin de stubs y "exportarlos" a1 cargador de clase EAR en el que serin visibles a todas las aplicaciones del EAR. Las interfaces pDblicas y 10s archivos de implementaci6n de stubs son las clases que necesita un cliente para hacer uso de un EJB. Las aplicaciones Web podrin entonces cargar las clases requeridas para utilizar cualquier EJB.

Empaquetado e irnplementacion J2EE


Las bibliotecas de utilidad de dependencia pueden ser cargadas en diferentes lugares dependiendo del lugar en que se especifique la libreria. Si una dnica aplicaci6n Web incluye una biblioteca de dependencia en un directorio WEB- INF\lib,entonces esa biblioteca es exclusiva de esaaplicaci6n Web. Noes necesario que otras aplicaciones accedan a 10s contenidos de esa biblioteca y por ello el cargador de clase EAR no debe cargarla. En esta s i t u a c h , el cargador de clase de la aplicaci6n Web cargari el archivo JAR de utilidad. Otras aplicaciones Web deben incluir la misma dependencia en su propio WEB- I N F \ ib ~ para mantener este aislamiento. Las bibliotecas de utilidad de dependencia que deben ser cornpartidas por aplicaciones EJB y Web necesitan ser cargadas en el nivel del cargador de clase EAR. Resulta que un cargador de clase EAR cargari cualquier biblioteca especificada como dependencia de un EJB con el objetivo de otorgar lavisibilidad adecuada a aquellas clases de dependencia. Esto permite a un desarrollador de EJB empaquetar cualquier clase de excepci6n comun, clases personalizadas de parimetros de entrada que Sean visibles para una aplicaci6n ar Web v el EBT en una biblioteca de dependencia. Esta biblioteca se denomina com6nmente common. i per0 no tiete que llamarse asi obligatoriamente. Ademis de las interfaces publicas y las clases de implementaci6n de stubs, la biblioteca de utilidad comun tambien sera cargada en el nivel EAR, que permite visibilidad de aplicaci6n Web a todas las clases utilizadas por el EJB. Los archivos de adaptador de recursos empaquetados en el archivo EAR junto con EJB y aplicaciones Web son cargados automiticamente en el nivel del cargador de clase EAR.

La opcion posterior a EJB 2.0


El Borrador 2 Final Publico de EJB 2.0 introdujo el concept0 de interfaces locales y dio un giro interesante a1 problema de carga de clases EAR. Las interfaces locales permiten el acceso a cliente co-localizados y EJB utilizando la semintica de pasar-por-referencia en lugar de la semintica de pasar-por valor. Tener visibilidad de las interfaces publicas y de las clases de implementaci6n de un EJB no es suficiente para que un cliente de un EJB ejecute invocaciones tipo pasar-por-referencia. El cliente necesita una referencia directa a las clases de implementaci6n del contenedor EJB. Con interfaces locales, 10s clientes de EJB necesitan acceder a muchos mis elementos que antes. Esta restricci6n significa que el esquema de carga de clases utilizado con anterioridad a EJB 2.0 no funcionari. Para resolver este problema, 10s cargadores de clase de cualquier aplicaci6n que actuan corno clientes para un EJB deben ser cargados como dependientes del cargador de clase EJB:

Cargador de Clases EAR


- -

1.~
1

......

~~~~

. ~ .

. . ? L

.. .. . .. .

Cada EAR obtiene su propla Instancia

Bibliotecas de dependencia y adaptador de recursos cargados aqui

. .

- - -- -

1(
v
rdeClasesweb1

Cargador de Clases EJB Todos 10s JAR L I B cargados por un h c o cargador de clases

I
i
cargador de clases
J

1
Las b~bllotecas de dependencla espec~ficadas por U ~ W E B - I N F \ ~lbespecificosoncargadas I aqui para estar asladas

Capitulo 24
En este modelo, 10s cargadores de clase de la aplicaci6n Web dependen del cargador de clases EJB. Esto permite a todas las aplicaciones Web tener visibilidad de 10s archivos que necesitan para comportarse como clientes de 10s EJB. Cada aplicacidn Web, sin embargo, sigue siendo cargada en un cargador de clase personalizado para conseguir el aislamiento. La estructura en conjunto de esta implementaci6n es mis sencilla de comprender, ya que no requiere que el cargador de clases EJB exporte ning6n archivo a1 cargador de clase EAR.

Una ambigiiedad en la especificacion JZEE


Ciertas implementaciones han expuesto una ambigiiedad en la especificacih JZEE, yaque es ambigua en lo referente a c6mo deben cargarse las bibliotecas de dependencia de una aplicacion Web. Esti muy claro que una biblioteca de utilidad especificada por WEB-INF\lib debe permanecer aislada y debe ser cargada s61o por el cargador de clase de la aplicac@ Web. Sin embargo, si una biblioteca de utilidad es especificada como biblioteca de dependenc~a de la aplicaci6n Web, n o se establece si la biblioteca debe cargarse por el cargador de clase de la aplicaci6n Web o exportada a1 cargador de clase EAR. Esto puede afectar a1 comportamiento. Si se sabe que una biblioteca de utilidad de dependencia s610 sera cargada una vez para todas las aplicaciones Web, las aplicaciones Web pueden beneficiarse de saber que una clase semifallo s610 creari un unico objeto que pueda ser compartido por todas las aplicaciones Web. Sin embargo, si cada cargador de clase de la aplicacidn Web aislara la biblioteca de utilidad, una clase semifallo, que es una clase destinada a crear unicamente una dnica instancia en el equipo virtual, crearia un unico objeto en cada aplicaci6n Web. En la actualidad, el servidor de aplicaci6n de Silverstream y la Implementaci6n de Referencia JZEE cargan bibliotecas de utilidad especificadas como bibliotecas de dependencia de una aplicaci6n Web en el nivel de cargador de clase EAR. WebLogic Server 6.0 carg6 estas bibliotecas como parte del cargador de clases de la aplicaci6n Web. Sin embargo, WebLogic Server 6.1 ha modificado este enfoque para apoyar la carga de bibliotecas de dependencia de aplicaci6n Web en el nivel EAR. Esto es coherente puesto que el aislamiento de la aplicaci6n Web siempre puede conseguirse situando las bibliotecas de utilidad en el directorio WEBINF\lib. Esto ofrece lo mejor de 10s dos mundos: una biblioteca de dependencia cargada en el nivel del cargador de clase EAR o una biblioteca de dependencia cargada en el nivel del cargador de clase de la aplicaci6n Web.

Configuracion de paquetes JPEE


Ahora que ya tenemos un conocimiento bdsico de la implementaci6n de la arquitectura JZEE, 10s roles y el comportamiento de 10s cargadores de clases, podemos configurar e implementar aplicaciones de empresa. Para ello, necesitamos comprender el proceso de creaci6n de archivo EAR y 10s contenidos de 10s descriptores de implementaci6n que describen sus contenidos.

El proceso de desarrollo de aplicaciones de empresa


El proceso completo que se utiliza para construir una aplicaci6n de empresa es el siguiente:
1. Los desarrolladores construyen componentes individuales; pueden ser EJB, piginas JSP, servlets y adaptadores de recursos.

2. Ciertos componentes son empaquetados en un archivo JAR junto con un descriptor de implementation para un m6dulo JZEE. U n m6dulo JZEE es una colecci6n de uno o mis componentes JZEE del mismo tipo de componente, por lo que un m6dulo EJB puede comprender

Empaquetado e implementation J2EE


rnis de un EJB; un modulo de aplicacion Web puede comprender mGtliples piginas JSP y sewlets; un archivo de adaptador de recursos puede comprender mGltiples adaptadores de recursos.

3, U n o o rnis m6dulos J2EE son combinados en un archivo EAR junto con un descriptor de implementation de la aplicacion de empresa para crear una aplicaci6n J2EE. La aplicacion J2EE rnis sencilla esti compuesta de un Gnico m6dulo J2EE. Aplicaciones J2EE rnis complicadas estin compuestas por mGltiples m6dulos J2EE. Una aplicaci6n J2EE compleja comprende mGltiples m6dulos J2EE y las librerias de dependencia utilizadas por las clases contenidas en 10s m6dulos. Una aplicaci6n J2EE pueden tambikn contener archivos de ayuda y otros documentos para asistir a1 implementador.
4. La aplicaci6n J2EE se implementa en un product0 J2EE. La aplicacion J2EE es instalada en la plataforma J2EE y despues integrada con cualquier infraestructura existente en un sewidor de aplicacion. C o m o parte del pfoceso de implementaci6n de la aplicaci6n J2EE, cada m6dulo J2EE es implementado de forma individual s e g h las directrices especificadas para la implementaci6n del tip0 correspondiente. Cada componente debe ser implementado en el contenedor correct0 que se corresponda con el tip0 del componente.

Por ejemplo, si tiene un m y . ear con un m y . j a r y un m y . w a r contenidos en el archivo EAR, a1 implementar la aplicacion, la herramienta de implementation del sewidor de la aplicaci6n copiari el archivo m y . ear en el sewidor de la aplicacion. A continuaci6n, el mecanismo de implementacidn del sewidor de la aplicacion extraeri 10s m6dulos m y . j ar y m y . w a r y 10s implementari por separado siguiendo las directrices de carga de clases de esa plataforma. Si cada modulo se implementa con exito, entonces se considera que la aplicacidn J2EE se ha implementado con exito. El proceso de desarrollo e implementaci6n de la aplicaci6n de empresa J2EE podria funcionar ask

Capitulo 24

. q de : Implernentacion

ariadir/eliminar ingredientes
, - - - - - - - - - - - - - - - - - - - - -

implementar m6dulos independie

Los componentes se construyen y empaquetan en un m6dulo J2EE con un descriptor de implementaci6n; una herramienta de implementaci6n puede utilizarse pa;a crear estos m6dulos. La herramienta tambiCn se puede utilizarse para implementar y desimplementar m6dulos J2EE independientes; para tomar uno o mbs m6dulos J2EE y empaquetarlos en una aplicaci6n J2EE con otro descriptor de implementaci6n; para afiadir o eliminar elementos de la aplicaci6n J2EE; o implementar toda la aplicacidn en un servidor de aplicaci6n.

La estructura de un paquete JZEE


La estructura de un paquete de aplicaci6n de empresa J2EE es muy directa; esti compuesta por uno o mbs m6dulos J2EE y un descriptor de implementaci6n llamado a p p l i c a t i o n . xml en el directorio METAINF\. Los archivos se empaquetan con el formato JAR y se almacenan en un archivo con extensi6n .e a r . Puede incluir bibliotecas de dependencia en el archivo EAR. La estructura general de un archivo EAR es la siguiente:

EJB .jar Files W e b Application .war Files Resource Adapter . rar Files Application Client .jar Files Dependency Library .jar Files META-IN\ application.xm1

U n ejemplo de archivo EAR que tenga un m6dulo EJB y un m6dulo de aplicaci6n Web sin bibliotecas de dependencia podria ser asi:
FirstEJB. j a r FirstWeb .war M E T A - I N F\ application.xm1

Los modulos J2EE almacenados en el archivo EAR n o tienen que estar necesariamente en el directorio raiz de la estructura. Por ejemplo, 10s contenidos de un archivo EAR que tiene un m6dulo EJB y un archivo de adaptador de recursos almacenado en subdirectorios podria ser asi:

Finalmente, un archivo EAR que tiene diversos componentes y bibliotecas de dependencia podria ser:
ejbs\ ThirdEJB. j ar FourthEJB. j ar resources\ LegacyAdapter.rar Web\ WebAppl.war WebApp2.war lib\ xmlx. j ar common. j ar META-IN\ application.xm1

El archivo EAR es creado utilizando una herramienta de implementaci6n facilitada por un proveedor de herramientas o, alternativamente, utilizando la herramienta j a r provista en el JDK. Los pasos de creaci6n son:

O Crear un directorio de hospedaje que contendrP 10s contenidos del archivo EAR O Situar todos 10s m6dulos J2EE en el directorio de hos~edaje y crear el directorio META- INF\ O Crear el descriptor de implementaci6napplicat i o n . xml situarlo enMETA- INF\
Despuks de haber construido el directorio de hospedaje, dirijase a la raiz del directorio y ejecute la utilidad j a r para crear el archivo EAR U n ejemplo de ejecuci6n de la utilidad j a r para el ejemplo complejo analizado anteriormente podria ser:
j a r cvf Application. ear ej bs resources Web lib META-IN

Una vez se ha creado el archivo EAR, tiene total libertad para implementar la aplicaci6n J2EE en el sewidor de la aplicaci6n.

Trabaiar con el d e ~ c r i ~ t de o r im~lementacion EAR


En una situaci6n ideal, se utilizaria una herramienta @fica de implementaci6n para construir 10s archivos application.xml. Sin embargo, puede haber situaciones en las que necesite construir o mantener manualmente a p p l i c a t i o n . xml y, por ello, es importante comprender las etiquetas que se utilizan. El descriptor de implementaci6n a p p l i c a t i o n . xml es sencillo. Un descriptor vilido no requiere muchas etiquetas. Las posibles etiquetas contenidas en el DTD del descriptor son:

Todos 10s descriptores de implementaci6n vilidos de aplicaci6n J2EE debe contener la siguiente declaraci6n~0~~~~~:
< ! D O C T Y P E a p p l i c a t i o n P U B L I C "-//Sun M i c r o s y s t e m s , I n c . / / D T D J 2 E E Application 1.3//ENW "http://java.sun.com/dtd/application~l~3.dtd">

La configuraci6n de un sencillo descriptor de implementaci6n a p p l i c a t i o n . xml s610 conlleva 10s siguientes pasos:

1. La e t i q u e t a < a p p l i c a ti o n > se utiliza para declarar una aplicaci6n de empresa. La etiqueta < a p p l i c a t i o n >puede contener<icon>,< d i s p l a y - n a m e > y < d e s c r i p t i o n > p a r a s e r utilizados por una herramienta de implementaci6n y proporcionar informaci6n sobre la aplicaci6n. El contenido de estas etiquetas es el mismo que el de 10s mismos etiquetas de 10s descriptores de implementacidn de un EJB, una aplicaci6n Web y un adaptador de recursos.
2. Cada m6dulo J2EE incluido en la aplicaci6n de empresa debe tener una etiqueta<module> equivalente que describa el m6dulo. Los EJB son descritos utilizando la etiqueta < e j b>, las a~licaciones Web son descritas utilizando la etiaueta <Web>. 10s adamadores de recursos son descritos utilizando la etiqueta < c o n n e c t o r > y 10s programas cliente de aplicaci6n son descritos el , contenido de las otras etiquetas utilizando la etiqueta< j ava>. A excepci6n de la e t i q u e t a < ~ e b > es un URI relativo que nombra el archivo que contiene el m6dulo J2EE dentro del archivo EAR. El URI debe ser relativo a la raiz del archivo EAR.

3. Si su aplicaci6n de empresa contiene un m6dulo JZEE de aplicaci6n Web, necesita facilitar un <Web-uri> y u n < c o n t e x t - r o o t > . L a e t i q u e t a < ~ e b - u r i > es unURI relativo que nombrael archivo que contiene el m6dulo J2EE en el archivo EAR. Se trata del mismo tipo de URI que se especificaparalasetiquetas<e j b > , < c o n n e c t o r > y < j ava>.Laetiqueta<context-root>

Empaquetado e implernentacion J2EE


especifica el nombre del contexto bajo el que se ejecutari la aplicaci6n Web. Posteriormente, todas las solicitudes de piginas JSP y servlets para esa aplicaci6n Web deben estar precedidas por este contexto de Web. Por ejemplo, si despliega una aplicaci6n Web con:

todas las solicitudes p y a piginas JSP y servlets siempre estarin precedidas de:

Cada aplicaci6n Web empaquetada en un archivo EAR debe tener un valor <context-root> exclusive. Dos aplicaciones Web empaquetadas en el mismo archivo EAR no pueden tener valores <context-root> idhticos. Si s610 hay una aplicaci6n Web en el archivo EAR, el valor de <context-root> puede serunacadenavacia.

El uso mis comb de archivos EAR se daria en una situaci6n en la que una aplicaci6n de empresa tenga un Gnico m6dulo EJB y un Gnico m6dulo de aplicacion Web que haga uso de 10s componentes EJB implementados en el m6dulo EJB. En este ejemplo, 10s EJB y las aplicaciones Web no dependen de ninguna biblioteca de dependencia. Esta secci6n describe 10s pasos necesarios para la construcci6n de este ejemplo.
Empaquetar 10% componentes

Este ejemplo tiene un servlet que invoca un mktodo invoke ( ) en la interfazremota de un EJB de sesi6n sin estado. El servlet y el EJB imprimen instrucciones a la consola para que indique que estin siendo ejecutados con Cxito. Si la consola recibe una excepci6n, probablemente el empaquetado de 10s componentes no se ha realizado correctamente. Todos 10s archivos fuente EJB de este ejemplo se encuentran en el paquete wrox. El servlet se encuentra en el paquete sin nombre. Los archivos Java utilizados para implementar este ejemplo incluyen:
EnterpriseServ1et.java

La clase de implementacion del servlet que invoca el EJB


Enterprise-java

La interfaz remota del EJB


EnterpriseHome.java

La interfaz inicial del EJB


EnterpriseBean. java

La clase de implementaci6n del EJB


Para saber c6mo componer servlets y EJB, remitase a 10s capitulos correspondientes de este libro. Esta seccidn s61o mostrari 10s fragmentos relevantes de codigo que permitan a1 lector seguir el ejemplo. La composici6n de EJB y de 10s descriptores de la aplicaci6n Web, la creaci6n de 10s archivos JAR y de archivos WAR no estin demostrados en este capitulo. El codigo fuente para la clase de i m p l e m e n t a c i 6 n ~ n t e r p r i s e ~ e a j nava . es el siguiente:
package import public wrox; javax.ejb.*; class EnterpriseBean implements SessionBean

Capitulo 24

private InitialContext ctx; public public public public public void e j b C r e a t e 0 {} void ejbRemove() {} void ejbActivate ( ) { I void ejbpassivate ( ) { I void setSessionContext (SessionContext c ) { 1

public void invoke() [ Systern.out .prir7tlr1("Executing in EJB.");

El codigo fuente para la clase del servlet Enterprises ervlet . j ava es el siguiente:
import import import import javax.servlet.*; javax.servlet.http.*; j ava. io.*; j avax. naming. * ;
[

public class Er~terpriseServlet extends HttpServlet public void

service(HttpServ1etRequest req, HttpServletResponse throws IOExceptionl ; res .setContentType ("text/htmll') Printwriter out = res.getWriter ( ) ;

res)

try i System.out.println("Serv1et Executing in Server"); InitialContext ctx = new InitialContext ( ) ; wrox. EnterpriseHome eHome wrox.Enterprise e. invoke(); e
=

(wrox.EnterpriseHome) ctx.lookup("EnterpriseEJB"); eHome.create0;


=

1 catch(Exception e) { out .println ("Exception: " t e ); System. out. println ("Exceptior~: " t e ) ; 1
out .println ("<html><head><title>Title</title></head>") ; out .println ("<body>") ; out .println ("<hl>See console to ensure EJB was invoked. </hl>") ; out .println ("</body></html>");

1 1

Despu.6~ de desarrollar el codigo EJB 10s descriptores de irnplernentaci6n relevantes (que no incluirnos aqui), el EJB debe ser ernpaquetado en un archivo llamado EnterpriseBean. jar. El EJB es configurado para asociarse a EnterpriseEJB en el espacio de nornbre JNDI. DespuCs del desarrollo del cddigo de servlet y de 10s descriptores de despliegue relevantes (tarnpoco incluidos aqui), el servlet debe ser ernpaquetado en un archivo llarnado ~ e b ~ p war. p . La clase de servlet es registrada para ejecutarse con la asociaci6n /enterpriseservlet /. EnsamblJe de la aplicacion Despuks de cornpletar el proceso de construcci6n del cornponente, tarnbikn debe desarrollarse el descriptor de implernentaci61-1de la aplicacion de ernpresa. Necesitarnos registrar el EJB y la aplicaci6n

Empaquetado e implementacion J2EE


Web como modulos de la aplicaci6n de empresa. Tambikn queremos que 10s componentes de la aplicaci6n Web se ejecuten bajo la raiz del contexto /Web/. El archivo a p p l i c a t i o n . xml para este ejemplo se convierte en:

c ! DOCTYPE a p p l i c a t i o n P U B L I C ' - / / S u n M i c r o s y s t e m s , I n c . //DTD J2EE A p p l i c a t i o n 1.3//EN1 'http://java.sur~.com/dtd/applicaticr~1 3 . d t i l 1 >

Despuks de crear el descriptor de implementacion a p p l i c a t i o n . xml,el directorio de construcci6n de la aplicacidn de empresa debe parecerse a este:

Para crear un archivo EAR l l a m a d o ~ n t e r p r i s ee a r utilizando la utilidad j a r , debe introducir en la consola el siguiente comando:
j a r

cvf E r ~ t e r p r i s e e. a r

E r ~ t e r p r i s e B e a r r . ja r

WehA&'p.war META-INF

Lo interesante sobre la herramienta de implementacidn provista por la Inplement a ci o n de Referencia J2EE es que nunca se supone que 10s desarrolladores deban componer 10s descriptores de implementaci6n ej b- j a r .x m l o appl i ca ti on. xml. Estos archivos siempre son generados automaticamente por el us~ario. En el caso de esta aplicacidn de empresa, el archivo a p p l i ca ti on. xnd que se sitria en el archivo EAR es generado automkticamente para el desarrollador.
lmplementacidn de la aplicacion
Despuks de que el archivo EAR haya sido construido, necesita implementarse. Recuerde que el proceso de implementacibn es especifico del vendedor y que cada vendedor proporciona herramientas personalizadas para ello. La utilidad d e p l o y t o o l J2EE tiene una opci6n para implementar una aplicaci6n para la Implementaci6n de Referencia.

qecutar la aplicacion
Despues de que la aplicaci6n de empresa haya sido implementada con exito, la ejecuci6n del cliente conlleva invocar el servlet que ha sido desplegado en la aplicaci6n Web. Puesto que la raiz de contexto de la aplicaci6n de empresa es /Web, el servlet es invocado como parte de la misma. Por ejemplo, para invocar el servlet, debe introducir lo siguiente en la ventana del navegador:

Deberi ver la siguiente pantalla en el navegador despuks de que se ejecute el servlet:

Capitulo 24

Etiquetas opcionales de la etlqueta de Implementation \


Pueden utilizarse dos etiquetas opcionales de descriptor de implementacidn en ciertas situaciones. Son
<alt-add>y<security-role>.

< a l t - a d d > es una sub-etiqueta de <module>. El valor de esta etiqueta es un URI que apuntaria hacia otro archivo de descriptor de implementacidn para el mddulo referenciado desde la raiz del archivo EAR. El archivo no tiene por quC tener el mismo nombre que tiene dentro del mddulo J2EE. Por ejemplo, todos 10s descriptores de implementacidn del mddulo EJB deben llamarse e j b- j a r .xml. El valor de esta etiqueta puede ser un archivo con un nombre distinto a e j b- j a r .xml si esti referenciando a un descriptor de implementacidn alternativo para un mddulo EJB. El archivo del descriptor de implementacidn ignoraria a1 contenido en el mddulo J2EE. ~ s t es e un tipo de descriptor de implementacidn posterior a1 ensamblaje. Esta etiqueta puede utilizarse para referenciar una versidn externa del descriptor que debe utilizarse si un implementador quiere utilizar un descriptor de implementacidn diferente del contenido en un EJB, una aplicacidn Web, un adaptador de recursos o un mddulo de cliente de aplicacidn. Si este valor no se especifica, entonces la herramienta de implementaci6n debe utilizar 10s valores especificados en 10s archivos JAR, WAR o RAR provistos en el archivo EAR. Por ejemplo, para especificar una aplicacidn Web con un descriptor de implementacidn externo, alternativo, que estC localizado en la raiz del archivo EAR, debe escribir lo siguiente:

< s e c u r i t y - r o l e > permite a1 implementador especificar loirales de seguridad de nivel de aplicaci6n que deben utilizarse para todos 10s mddulos contenidos en el archivo EAR. Si un archivo EAR contiene m6ltiples mddulos EJB y/o m6ltiples mddulos de aplicacidn Web, cada hno de esos mddulos puede tener sus propios roles de seguridad definidos en si mismos. Una de las responsabilidades del implementador consiste en asegurarse de que 10s nombres de todos 10s roles de seguridad contenidos en todos 10s mddulos J2EE son exclusives y tienen significado para la aplicacidn completa. Los roles de seguridad pueden ser "extraidos" del nivel de mddulo J2EE y llevados a1 nivel de aplicacidn de empresa e incluidos en esta etiqueta. Si existe un valor de rol de seguridad duplicado en uno de 10s mddulos JZEE, ese valor puede ser eliminado si el valor es proporcionado en el nivel de aplicacidn de empresa. Esta etiqueta requiere una sub-etiqueta < r o l e - n a m e > para proporcionar realmente el nombre simbdlico del rol de seguridad. U n ejemplo de configuracidn de una etiqueta<s e c u r i t y - r o l e > es el siguiente:
<security-role>

Empaquetado e implementation J2EE


<description> This is administrator's security role </description> <role-name>Administrator</role-name> </security-role>

Cuestiones relacionadas con el orden de 10s modulos


La especificaci6n JZEE no establece ninguna especificaci6n sobre c6mo deben implementarse 10s m6dulos JZEE contenidos en un archivo EAR. En concreto, el orden en el que 10s m6dulos deben ser implementados n o se describe explicitamente en la especificaci6n. Puede ser un problema si un componente de un m6dulo necesita usar otro componente en otro m6dulo todavia por implementar. La mayoria de 10s senidores de aplicaci6n implementarin 10s archivos EAR utilizando el mismo procedimiento:
1. Todos 10s adaptadores de recursos contenidos en el archivo EAR serin implementados en la infraestructura de conectores. Si se configuran mdtiples adaptadores de recursos, se implementarin en el orden en que aparecen en el descriptor application. xml.

2. Se implementarin todos 10s m6dulos EJB. Los EJB se implementan despuks de 10s adaptadores de recursos puesto que 10s EJB pueden hacer uso de un determinado adaptador de recursos durante su etapa de inicializaci6n. Si se configuran m~ltiples m6dulos EJB, se implementarin el orden en que aparezcan listados en el descriptor de implementaci6n applicat ion. xml.
3. Se implementarin todos 10s m6dulos de aplicaci6n Web. Las aplicaciones Web se implementan despuks de 10s EJB y de 10s adaptadores de recursos puesto que las aplicaciones Web hacen uso de estos recursos durante su fase de inicializaci6n. Si se configuran mdtiples m6dulos de aplicaci6n Web, se implementarin en el orden en que aparezcan listados en el descriptor de implementaci6n application.xm1.

Cuestiones relacionadas con paquetes de dependencia


La cuesti6n mis frecuente relacionada con el empaquetado J2EE hace referencia a las clases de utilidad y de compatibilidad. A la hora de empaquetar una aplicaci6n Web o una aplicaci6n EJB, id6nde deben situarse estas bibliotecas? Si ubica estas clases en la ruta estindar de su senidor de aplicaci6n, probablemente perderin cualquier capacidad de descarga que tienen dichas aplicaciones Web y EJB que son controladas por 10s cargadores de clases utilizados para cargarlas en la implementaci6n. Si sus aplicaciones Web/EJB necesitan cambiar la versi6n de las bibliotecas que utilizan, entonces sera necesario volver a implementar la biblioteca dependiente cuando se vuelva a implementar la aplicaci6n Web/EJB. En esta situaci611, almacenar clases dewtilidad en la ruta de clase estindar n o es una opci6n viable puesto que el senidor de aplicaci6n completo tendria que ser reiniciado para cada implementaci6n de una aplicaci6n Web/EJB, lo que claramente no resulta ideal. Teniendo en cuenta la definici6n estindar de JZEE, id6nde se supone que deben situarse las bibliotecas de dependencia de mod0 que puedan volver a implementarse con una aplicaci6n en el period0 de ejecuci6n? Existen dos soluciones creativas, aunque indeseables en 6ltima instancia:

Capitulo 24
Las bibliotecas de dependencia ernpaquetadas corno archivos JAR pueden situarse en el directorio
WEB- I N F \ l i b de una aplicacion Web. Por lo general, el d i r e c t o r i o ~ E ~ IN - F \ l i b debe utilizarse

principalrnente para el almacenamiento de clases de servlet, pero 10s servlets y las piginas JSP buscarin clases en este directorio a la hora de cargar clases nuevas. Si la biblioteca de utilidad que esti utilizando so10 la necesitan sus servlets y piginas JSP, esta soluci6n sera entonces suficiente. Sin embargo, si las misrnas bibliotecas tarnbien son necesitadas por EJB, consurnidores JMS o clases de arranque y cierre, entonces esta opci6n no funcionari puesto que el directorio WEBI N F \ l i b no es visible para estos elernentos.
0 Una copia completa de todas las bibliotecas de utilidad se situa en cada archivo JAR EJB adernis de en el archivo WEB- INF\lib. Cuando se irnplementa un EJB, un cargador de clases EJB so10 buscara cualquier clase de utilidad referenciada dentro de su propio archivo JAR. N o buscari en 10s archivos JAR de otras aplicaciones EJB que hayan sido irnplementadas ni en el directorio WEBINF\lib. Si todas sus aplicaciones EJB requieren el uso de la misrna biblioteca, entonces ubicar una copia de las clases de esa biblioteca en cada archivo JAR cubriri sus necesidades. Las clases de utilidad podrin volver a irnplementarse junto con el EJB.

Aunque la segunda situacibn alcanza la capacidad de reimplementaci6n de las bibliotecas de dependencia, es increiblemente ineficiente. El propdsito de tener multiples archivos JAR para ernpaquetar es fornentar la rnodularidad de aplicaciones y situar la rnisrna clase en multiples archivos JAR destruye esta posibilidad. Adernis, tener multiples copias de las rnisrnas clases sobrecarga innecesariamente sus aplicaciones. Finalrnente, existe un paso afiadido para el proceso de construccion, puesto que cada archivo JAR tendri que ser reconstruido si desea cambiar incluso una unica biblioteca.

Soluciones
Una de las posibles soluciones a este problerna consiste en elirninar la necesidad de que haya multiples JAR en aplicaciones J2EE haciendo convergir todos 10s EJB y sus clases de utilidades en un paquete unificado. La especificaci6n EJB 2.0 esta dirigiendo algunos proyectos para conseguirlo. Esta version de la especificacion establece que 10s EJB de entidad que participen en una relacion lo hagan utilizando interfaces locales y ello requiere que ambos EJB que intervienen en la relacion Sean ernpaquetados en el rnisrno archivo JAR. Anteriores borrado~es de EJB 2.0 perrnitian a EJB de diferentes archivos JAR participar en relaciones, fornentando una mayor rnodularidad del sisterna pero, finalrnente, lirnitaba las optirnizaciones de persistencia disponibles para beans de entidad CMP en una relacion. El Borrador 2 Publico Final elirnin6 las relaciones rernotas; por ello, rnuchos vendedores estin pensando en facilitar herrarnientas que llevan a cab0 la convergencia JAR EJB. Estas herrarnientas tornarin corno entrada dos archivos JAR EJB validos y fusionarin sus clases y descriptores de irnplernentacion en un unico paquete unificado. Podria potencialmente utilizar una de estas herrarnientas de convergencia para volver a ernpaquetar sus aplicaciones JAR existentes para reducir la redundancia de las bibliotecas de dependencia entre archivos JAR EJB. En el rnornento de escribir este libro, estas utilidades de convergencia todavia estin siendo desarrolladas. Cornpruebe con su proveedor de servidor de aplicaci6n si hay alguna utilidad de convergencia disponible para su uso. Recuerde que, incluso si todos 10s EJB convergen en una unica aplicacih JAR, tendri que elirninar copias de su biblioteca de dependencia entre 10s EJB, per0 todavia seri necesario que exista una copia en una IN F \ l i b si una aplicacion Web depende de ella. Adicionalrnente, la necesidad de bib1iotecaw~~ rnodularidad de aplicaciones JEB sigue existiendo puesto que rnuchas cornpaiiias desean volver a implementar EJB de forma individual. Puesto que cada EJB de un JAR se volveri a irnplementar cuando vuelva a implernentarse ese archivo JAR, podria llevarse a cab0 una innecesaria cantidad de procesarniento si su unico deseo es volver a implernentar un unico EJB.

Empaquetado e implernentacion J2EE


Una solucion mejor
C o n el lanzamiento de JDK 1.3, Sun Microsysterns redefini6 el "rnecanismo de extensi6n1'que es la funcionalidad necesaria para apoyar paquetes opcionales. El rnecanisrno de extensi6n esti disefiado para ser compatible con dos realidades:
0

Q u e 10s archivos JAR puedan declarar su dependencia de otros archivos JAR perrnitiendo 4ue una aplicaci6n estk formada por mdtiples m6dulos para clases

CI Q u e 10s cargadores de clases sean rnodificadas para buscar paquetes opcionales y rutas de aplicacion

Adicionalrnente, la especificacion J2EE 1.3 establece que 10s servidores de aplicacion deben ser compatibles con el rnecanismo de extensi6n tal y corno se define para archivos JAR. Esto requiere cualquier herrarnienta de implementaci6n que referencie un archivo JAR que sea capaz de cargar cualquier biblioteca optional definida a travks del mecanisrno de extension. Tambikn irnplica que si un servidor de aplicaci6n o una herrarnienta de irnplernentacidn sea compatible con las operaciones de desimplementaci6n y reimplementaci6n de aplicaciones EJB que utilicen bibliotecas a travks del mecanisrno de extensibn, por lo que esa herramienta o servidor de aplicaci6n debe tambikn ser compatible con la desimplementacidn y reimplementacidn de cualquier biblioteca dependiente. El apoyo para el rnecanismo de extensi6n no existe para EAR o aplicaciones de adaptadores de recursos tal y corno define la especificacion JZEE, puesto que estas aplicaciones no son cargadas directamente por una instancia de C l a s s l o a d e r . Las aplicaciones Web tienen la libertad de utilizar el mecanisrno de extensi6n o el directorio~EBI N F \ l i b a1 especificar una biblioteca de dependencia. Corno hemos analizado anteriorrnente, el mod0 en que es cargada una biblioteca de dependencia variari dependiendo de si la biblioteca es especificada utilizando el rnecanismo de extensidn o el directoriowEB- I N F \ l i b . Las aplicaciones de ernpresa necesitan volver a ernpaquetar cualquier biblioteca que necesite la aplicacion Web o la aplicacion EJB corno parte del archivo EAR. Una vez ernpaquetada, el mecanismo de extensi6n proporciona un rnodo estindar para que 10s archivos WAR de aplicaci6n Web y 10s archivos JAR de aplicacion EJB especifiquen quk bibliotecas de dependencia existentes en el archivo EAR de la aplicacidn de empresa son necesarias.
Comprender la ruta de clase manifiesta

<Corn0funciona el rnecanismo de extension con aplicaciones EJB? U n archivo JAR puede referenciar un archivo JAR dependiente afiadiendo un atributo c l a s s - p a t h : a1 archivo manifiesto contenido en cada archivo JAR. La utilidad jar crea autorniticamente un archivo rnanifiesto para situarlo en un archivo JAR y lo llama m a n i f e s t .mf por defecto. Este archivo puede ser editado para incluir una entrada de atributo c l a s s - p a t h : ademis de las otras entradas. De hecho, rnuchas herrarnientas de ernpaquetado de EJB estin teniendo en cuenta paquetes de dependencia corno parte del proceso de ernpaquetado. Crean un archivo m a n i f e s t . mf apropiado que contenga una entrada correcta de a t r i b u t o c l a s s - p a t h : . Por ejemplo, si crea un archivo JAR EJB y modifica m a n i f e s t .mf para incluir un atributo c l a s s P a t h :, la utilidad de generacion del contenedor provista por su vendedor de servidor de aplicaciondebe preservar esta entrada cuando genere un nuevo archivo de aplicacion EJB. C o n WebLogic Server 6.1, si proporciona una utilidad JAR EJB que ya contiene una entrada c l a s s - P a t h : en el archivo m a n i f e s t .mf, la ~ t i l i d a d w e b l o ~. ie cj b c preservari esta entrada cuando genere una nueva aplicacion EJB con 10s archivos del contenedor. En el momento de publicaci6n de este libro, todavia no existe una herramienta que Cree e inserte la entrada c l a s s - p a t h : en un a r c h i v o m a n i f e s t .mf. Por desgracia, esta tarea todavia tiene que realizarse rnanualrnente editando el archivo m a n i f e s t . mf de un archivo JAR. El atributo m a n i f i e s t o c l a s s - p a t h : enumera 10s URL relativos para buscar bibliotecas de utilidades. El URL relativo procede del cornponente que contiene la entrada c l a s s - p a t h : (no la raiz del archivo

Capitulo 24
EAR). Puede especificar mdtiples URL en una dnica entrada c 1a s s - P a t h : y un linico archivo manifiesto puede contener mdltiples entradas c 1a s s - P a t h :. El formato general para la entrada c 1a s s P a t h : es el siguiente:
Class-Path: list-of-jar-files-separated-by-spaces

Por ejemplo, un archivo JAR podria tener:


Class-Path: log4 j . j a r xmlx. j a r foo/bar/util. jar

Si utiliza el mecanismo de extensi6n en una aplicacion J2EE, la entrada manifiesta c 1a s s - pa t h : puede tambikn referenciar a directorios. Sin embargo, para aplicaciones J2EE de archivos JAR, la entrada manifiesta c 1a s s - P a t h : s61o puede referenciar a otros archivos JAR. Adicionalmente, la entrada c l a s s - p a t h : debe residir en una linea separada de otras entradas de atributo en el mismo archivo manifiesto. El mecanismo de extensi6n es una funci6n conveniente puesto que esti disefiado para manejar redundancias circulares creando una ruta de clase unificada que contenga todas las dependencias ordenadas segdn el primer anilisis. Por ejemplo, si la primera aplicaci6n EJB analizada en E J B l .j a r y referencia:
Class-Path: jaxp. j a r EJB2. j a r

. .\xmlx.

jar

un cargador de clases analizari entonces E J B 2 .j a r que referencia:


Class-Path: jaxp. j a r EJBl. j a r

La ruta de clase de la "aplicaci6n" resultante que utilizaria finalmente un cargador de clases seria:
Class-Path: jaxp. j a r EJB2. j a r

..\xmlx.

jar

EJBl. j a r

Ejemplo de dependencia
Este ejemplo esti disexiado para demostrar cualquier posible configuracidn de carga para una aplicaci6n de empresa. Muestra mliltiples m6dulos EJB, m~iltiples aplicaciones Web y bibliotecas de dependencia exclusivas y compartidas por estas aplicaciones. Implementar y ejecutar este ejemplo nos permite ver c6mo un sewidor de aplicaci6n carga diferentes clases de diferentes aplicaciones. Imprimiendo la jerarquia ClassLoader para diferentes clases a medida que son ejecutadas, podemos ver si todas las clases son cargadas en un dnico cargador de clases o en diferentes cargadores de clases y, si es asi, d l es la jerarquia de 10s cargadores de clases. Nuestro ejemplo consiste en dos m6dulos EJB, dos m6dulos de aplicaci6n Web y siete bibliotecas de dependencia utilizadas en diferentes situaciones. La estructura de un archivo EAR es la siguiente:
T

Dependl-container. j a r Depend2-container. j a r WebAppl.war WebApp:.war iltill.]ar Util2. j a r iltil3. j a r iltil4. j a r iltil5. jar iltil6. j a r rJtil7. j a r META-INF\ a p p l i c a t i o n . xrnl

Empaquetado e implernentacion J2EE


Hay un solo EJB en cada uno de 10s archivos Depend. Tambikn hay un servlet, T e s t S e r v l e t , que existe en cada aplicaci6n Web. Cada una de las bibliotecas de dependencia contiene una unica clase con un dnico mktodo que imprirne la jerarquia C l a s s L o a d e r . Este ejemplo provoca diferentes situaciones para ver c6rno son cargadas las clases en el context0 de un archivo EAR. En concreto, se prueban las siguientes situaciones:
0 iC6rno se carga una biblioteca de dependencia cuando es utilizada por un EJB y referenciada en esa

ruta de clase rnanifiesta del EJB?


0 i C 6 m o se carga una biblioteca de dependencia compartida por EJB en diferentes rn6dulos EJB? La

biblioteca de dependencia es especificada en la ruta de clase manifiesta de ambos EJB


0 iCdrno se carga una biblioteca de dependencia cuando es referenciada por una aplicaci6n Web y

alrnacenada en la ruta de clase manifiesta del m6dulo de la aplicaci6n Web?

iC6rno se carga una biblioteca de dependencia cuando es referenciada por una aplicaci6n Web y alrnacenada en el directorio WEB-INF\lib del m6dulo de la aplicaci6n Web? Web la referencian en ambas rutas de sus clases manifiestas?

0 iC6rno se carga una biblioteca de dependencia cuando un mddulo EJB y un m6dulo de aplicaci6n

Para ejecutar este ejemplo, implemente el archivo D e p e n d . e a r (disponible en h t t p : / ~ . w r o x . c o m )y despuks ejecute e l ~ e s t s e r v l e que t se irnplernenta en cada aplicaci6n Web. T e s t s e r v l e t invocarh 10s rnttodos apropiados de EJB que, a su vez, invocarin 10s mktodos sobre las clases de la biblioteca de dependencia. Por ejemplo, para ejecutar arnbos servlets, utilizaria 10s siguientes URI en un navegador:

Debe ver algo asi aparecer en la ventana del servidor:

Capitulo 24

El descriptor de irnplernentacidn de a p p l i c a t i o n . xml es el siguiente:

< ! DOCTYPE a p p l i c a t i o n PUBLIC "-//Sun Micrcsysterns, I n c . / / D T D J 2 E E A p p l i c a t i o n 1.3//ENm' "http://java.sun.aom/dtd/applicatinn 1 3.dtd1'?

Empaquetado e implernentacion J2EE

La ruta de clase manifiesta para el primer m6dulo EJB es:


Class-Path: Utill. jar Util3. j a r Util6. jar Util7. jar

Las entradas de ruta de clase manifiesta para el otro m6dulo EJB y 10s m6dulos de aplicaci6n Web varian y tienen diferentes combinaciones de siete bibliotecas de dependencia contenidas en el archivo EAR. Los servlets contenidos en cada aplicaci6n Web estin completamente documentados describiendo el hilo de ejecuci6n y el caso de prueba que se esti demostrando para cada biblioteca de dependencia.

El impact0 de las bibliotecas de dependencia


La ruta de clase manifiesta impulsari definitivamente una mejor modularidad de 10s paquetes Java en el futuro. Utilizando este modelo, 10s desarrolladores pueden emplear un sencillo esquema para determinar 10s EJB deben ser empaquetados en un unico archivo JAR y aquellos que deben ser empaquetados en archivos JAR separados:
0

Identificar un EJB de entidad que participe en una relacidn CMR. Identificar todos 10s EJB de entidad que son alcanzables a travis de relaciones CMR desde el EJB de entidad origen. Este grifico de EJB de entidad debe ser empaquetado en una unica aplicaci6n JAR EJB. Este proceso debe repetirse para cada grifico unico de relaciones de EJB de entidad. Empaquetar todos 10s EJB restantes en archivos JAR separados. coherente. La convergencia de multiples EJB en un unico archivo JAR debe suceder si es aceptable una situacion en la que volver a implementar todos 10s EJB cuando solo uno ha sido modificado.

0 Analizar sus requisitos ticnicos y de empresa y "converger" multiples archivos JAR si resulta

0 Cada archivo JAR EJB debe enumerar sus dependencias utilizando el atributo c l a s s - P a t h :

como hemos descrito anteriormente. U n cargador de clases inteligente resolveri cualquier dependencia circular o repetitiva. Por ejemplo, en el ejemplo de dependencia facilitado, ambas aplicaciones EJB referenciaban a la tercera biblioteca como dependencia. A pesar de este doble referencia, el cargador de clases EAR todavia era lo suficientemente inteligente para cargar la biblioteca una sola vez. La unica limitaci6n a la aue se enfrentan 10s desarrolladores ahora es la localizaci6n de un senidor de aplicaci6n que apoye por completo esta capacidad de empaquetado. Los desarrolladores necesitarin buscar senidores de aplicaci6n que se ejecuten en un JDK 1.3 y que apoyen por completo la especificaci6n J2EE 1.3. Como consecuencia, cualquier senidor de aplicaci6n certificado J2EE 1.3 s61o debe ejecutarse en un entorno JRE 1.3.

Capitulo 24

Este capitulo ha cubierto detalladamente las aplicaciones J2EE, incluido:


0

Como el mecanismo de empaquetado J2EE es iddneo para proporcionar una mejor interoperabilidad entre mGltiples mddulos J2EE Aplicaciones JZEE, m6dulos y archivos EAR

0 El proceso de desarrollo de la aplicaci6n J2EE


0

Ensamblaje e implementaci6n de la aplicacidn

0 Una aplicacidn de ejemplo

Ahora ya hemos visto la gama completa de tecnologias JZEE, desde 10s bloques bisicos de construcci6n de RMI, JDBC, J N D I y JAXP, pasando por 10s API de contenido Web de JSP y sewlets y Enterprise JavaBeans, hasta aplicaciones J2EE completas. Esperamos que este libro le haya inspirado en la creaci6n de sus propias aplicaciones Web. Divikrtase.

ckntrica, 49 declarativa, 49

Activation
descriptor, 152 grupo, 150 monitor, 149 sistema, 149 Activador Activatable, 156 ActivationID, 151 ADD, 110 Adrninistrador del sistema, 973 Alcance aplicacion, 507 pigina, 507 sesion, 507 solicitud, 507 Almacenarniento persistente, 776 Aiiadir entradas, 105 API, 45 Aplicacion

irnplernentaci6n de, 74 ensamblador de, 952 infraestructura de, 49 16gica de, 51 objetos de, 53 Aplicaciones cornponente de, 72 definici6n, 47 desarrollo con RMI, 130 distribuidas, 465 ensarnblador de , 72 Applet, 45,54 Archivo de politics, 128 args(), 111 Arquitectura de conectores, 1045 de contenedor, 60 de dos niveles, 50 de ernpresa, 53

indice alfabetico
de n niveles, 52 de tres niveles, 51 estilos, 1099 JMS, 1008 y diseiio, 1099 Asociacion, 93 Asociacion de distribution, 933 de nornbrado, 933 de seguridad, 933 de transaction, 933 Attributes, 100 Autenticacion basada en un forrnulario, 454 bisica, 453 de cliente HTTP, 453 resurnida, 453 booleanInput, 634 Buscadores, 861 BytesMessage, 1009

Carnpo oculto, 354 Capa de aplicaci6n,123 de datos, 52 de ernpresa, 51 de presentation, 123 de red, 123 de referencia rernota, 124 de representation, 51 de sesion, 123 de Stubs/Skeletons, 123 de transporte, 124 de vinculos de datos, 123 Carro de la cornpra, 372 Catch, 102 Chat, 381 checkbox, 634 cHTML, 60 Ciclo de vida, 65 Clases de carga dinirnica, 141 de conveniencia, 553 envoltorio, 328 Clusters, 65 Cliente definicibn, 122 EJB, 60 servidor, 46 Web, 60 Cloudscape, 229 Cola, 1010 Cornercio electrbnico, 46 Compilar, 113 Cornponentes

Bases de datos acceso, 198 consultar, 214 definition, 51, 68 drivers, 193 rnetadatos, 199 operaciones, 254 programacion, 191 BEA, 49 Beans de entidad, 829 de persistencia, 829 . de sesibn, 830 de sesi6n de estado, 67,68 dirigidos por mensaje, 68 Bind(), 109 Bloqueo optirnista, 916 pesirnista, 91 7

hdice alfabetico
contrato de, 61 de aplicaci6n,61,73 de audio, 63 Enterprise JavaBeans, 66 Comunicaci6n entre servidores heterogCneos, 932 Conexibn definicibn, 197 establecer, 205 Connection, 1025 Contenedor aplicaci6n de cliente, 59 applet, 59 definicih, 49, 58 EJB, 59 servicios de, 897 Web, 265 Contratos de componentes, 61 Cookies, 354 CORBA, 56 Core, 58 Correo cargar, 712 eliminar, 710 enviar, 701 guardar, 712 leer, 706 Cortafuegos, 53, 172 Costes, 47 Ctx, 111 bisicos, 609 condicionales, 619 de flujo de control, 610 de iteracibn, 612 extensiones, 539 JSP, 539 JSPTL, 608 manejadores, 547 Implementador, 72,963 destroy(), 61, 297 Destroycontext(), 112 DestroySubcontext(), 113 DirContext, 99, 109 Directorio, 442 Disponibilidad, 48 DNS, 79 Documentos adjuntos, 703 doGet(), 62 DOM, 57 doPost(), 63 Driver de bases de datos, 191 de Java, 196 mktodos de gestibn, 203 nativo, 194 DriverManager, 202

EAR, 74 EJB componentes, 748

Datasource, 238 dateFormat, 649 DELETE, 110 DeliveryMode, 1025 Descriptor de implementaci6n,61,63,273,434 Designador anidamiento, 578

contenedores, 724 definicibn, 720 nivel, 752 limitaciones, 745 trabajar, 731 Empresa arquitectura, 50 Formulario

lndice alfabetico
de entrada, 644 de registro, 516, 628 F Q D N , 78 FTP, 1004 IMAP, 671 Implements, 105 Import, 101 Indicadores de mensaje, 688 Inicializacion, 314 init(), 61, 297 InitialDirContext, 99 gerServletInfo(), 298 Gestor de recursos, 250 de transacciones, 25 1 getAll(), 101 getAttributes(),107 getconnection(). 234 getCrationTime(), 359 getId(), 359 getLastAccessedTime(), 359 getLoginTimeout(), 235 getlogwriter(), 235
getMaxiInactiveInterval(), 359

Instanciacih, 3 14 integerlnput, 633 Integracion, 48 Interfaz remota definir, 131 implementar, 131 Interfaz del usuario, 51 local, 839 remota, 130 Internet, 47 invalidate(), 359 Invocaci6n explicita, 64 IP, 71 isNew(), 359

getServletConfig(), 298

Hashtable, 101 HEAD, 267 HTML, 54 HTTP mktodos de solicitud, 266 protocolo, 266 respuesta, 267 HTTPServlet, 300 HttpSesion, 357 J2EE, 45 J2ME, 45 J2SE, 45 JAAS, 57, 70 JAF, 57 Java, 45 java.applet.Applet, 6 1 javasql, 197 Java extensi6r1, 55 referencias, 115 IbjectMessage, 1009 IBM, 49 IDL, 56,58 serializado, 115 JavaBeans, 49, 57, 67 JavaIDL, 71 JavaMail

IIOP, 58

lndice alfabetico
andisis, 672 API, 675 configuracihn, 673 definicihn,669 instalacihn, 673 recursos, 716 JavaServer, 50 javax.ejb.EJBHorne, 62 javax.ejb.EJBObject, 62 javax.ejb.EntityBean, 62 LAN, 128 Lanzarniento de solicitudes, 400 LDAP-SCOPE-BASE, 97 LDAP-SCOPE-ONELEVEL, 97 LDAP-SCOPE-SUBTREE, 96 LDAP definicion, 51, 80 tradicional, 1 14 LDIF, 82 Lenguaje de definicion de interfaces, 56 Lenguaje de programacion, 45 Biblioteca nativa, 747 list, 634 Listas de resultados actualizables, 230 definicion, 225 Localhost, 111 Localizaci6n de objetos remotos, 126 log, 649 L6gica de aplicaci6n,51 de empresa, 52 de presentation, 52 Lote de recursos, 637 Lotes. 231

javax.ejb.MessageDrivenBean, 62 javax.ejb.SessionBean, 62
javax.jmx.MessageListener, 62

javax.Servlet.http.HttpServlet, 62 javax.Servlet.jsp.HttpJspPage,62 javax.sq1,232 JAXP, 57 JCA, 70, 1049 JDBC, 57, 69 JDBCHelper, 513 JDK, 61 JMS, 57,70, 1005 JNDI, 58,69,83 JNDIAdd, 108 JNDIDel, 113 JNDIMod, 11 1 JNDISearchAuth, 101 JRMP, 71
JSP directrices, 477 especificacion, 471 presentacibn, 472 JSPTL definicion, 602 etiquetas, 608 inciarse, 603

main(), 111 Mandatory, 908 MapMessage, 1009 Mecanismo sincrono, 1141 Mensajes buscar, 699 copiar, 698 de listado, 696 rnoderacion, 430 mover, 698

integration, 604
JTA, 57 JVM, 61

indice alfabetico
registro de, 428 MessageConsumer, 1026 MessageProducer, 1026 Metadatos, 199 Mktodos de registro, 204 de salida, 326 para desplazamiento, 227 para gestionar drivers, 203 para obtener conexiones, 203 permisos, 922 relacionados con la posicidn del cursor, 227 Micro-dispositivos, 45 Microsoft, 46 MIME, 70,672 Modelo de programaci6n,45 ModificationItem, 110 ModifyAttributes, 111 Mods, 111 Modularidad, 50 Mddulos EJB, 73 Java, 73 Web, 73 MOM, 1004 myAttrbs.put, 106 Novel1 Directory Services, 69 NULL, 22 1 NUMERIC, 221

Objectclass, 81 Objeto activable, 153 activacidn, 149 gestionado, 49 registrar, 134 Objetos de aplicacidn,53 Objetos Application, 506 Config, 506 Out, 506 Page, 506 Pagecontext, 505 Request, 505 Response, 505 Session, 505 OperationNotSupportedException, 108 Oracle, 49 OTHER, 221

Name, 107 Naming, 127 Namingenumeration, 102 Navegador, 53 Necesidades de informacidn,47 NET, 46 Netscape Directory Services, 69 Never, 908 New, 108 NIS, 77 Niveles de aislamiento, 913

Pigina de bienvenida, 623 Piginas JSP, 66 Parimetros de objeto, 136 de primitivas, 136 en RMI, 136 remotos, 137 passwordhput, 633 Patrones, 1111 PDA, 45 Perfil de usuario, 645 Periodo de ejecuci6n, 55

hdice alfabetico
Person, 109 Plataforma, 45 Plataforma JZEE, 55 P ~ ~ Y 62 O, POP3, 671 PrinterFactory, 115 Println, 229 Procesos econ6micos, 47 Programaci6n lenguaje de, 45 modelo, 45, 48 para empresas, 46 productividad, 47 Protocolo de Internet, 70 de objeto remoto, 71 sin estado, 350 SOCKS, 173 Proveedor componente de aplicaci6n, 72 de herramientas, 73 del producto JZEE, 72 Proxy, 63 Public, 1O 1 Publicar, 1007 Puente JDBC-ODBC, 193 Punto a punto, 1006 REAL, 221 r e a h p u t , 634 Recolector de residuos, 138 Red de irea local, 128 Redes privadas, 47 REF, 22 1 Reference, 114 Registro, 126 Registry, 128 Relaciones, 873 REPLACE, 110 Required, 908 RequiresNew, 908 Reserva de recursos, 65 resourceBouble, 639 Retrollamadas remotas, 146 Retrollamadas, 748 reusabilidad, 49 Revisi6n, 314 RMI-IIOP, 71 RMI arquitectura, 122 definici6n,l2 1 RMISecurityManager, 135 RowSet, 256 RS232,1004 Ruta, 323

QueueBrowser, 1026 Queueconnection, 1026 QueueReceiver, 1027 Queuesender, 1027 Queuesession, 1027

SASL, 82 Scriptlets, 485 Scroller.first, 229 search(), 99 SearchControls, 100 SearchResult, 100 Seguridad de la empresas, 48 Seguridad definici6n,918 requisitos, 919

radioButton, 634 Reajustabilidad, 48

hdice alfabetico
roles, 919 y disefio de la aplicaci6n, 924 service (), 297 Servicios de contenedor, 61 declarativos, 61, 63 Servicios de directorio, 77 de nombrado, 78 Servidor definicibn, 122 intermediario, 195 Servlet anilisis, 292 ciclo de vida, 305 colaboracibn, 296 configuraci6n, 302 contexto, 296, 377 de arranque, 459 definicibn, 269 excepciones, 304 implementacibn, 295 interfaz, 296 programacibn, 29 1 ServletRequest, 319 Sesiones, 1009 Session, 1027 setlogwriter(), 235 setMaxiInactiveInterval(), 359 Sistema administrador, 73 Sistema remoto, 54 Skeletons, 123 SMALLINT, 221 SMTP, 670 Socket, 121,160 SpiritWAVE, 1003 SQL Server, 79 SSL, 59, 71 start(), 61 stop(), 61 StreamMessage, 1009 String, 100 STRUCT, 22 1 Stubs, 123 Sun, 46 Suscribir, 1007 SwiftMQ, 1003 Sybase, 51 System.exit, 111

TCP, 71 TechSupportBean, 514 Teinologias de componentes, 66 de comunicacibn, 70 de servicios, 69 TemporaryQueue, 1027 TemporaryTopic, 1027 Tepic, 1027 textInput, 633 TextMessage, 1009 TIME, 221 TIMESTAMP, 221 TINYINT, 221 Topicconnection, 1027 TopicPublisher, 1027 Topicsession, 1028 Topicsubscriber, 1028 Transacciones contexto, 249 controladas por el usuario, 9 11 definicibn, 246 demarcacibn, 248 distribuidas, 246 largas, 9 15 procesamiento, 248 propagacibn, 249 sin contenedor, 900

hdice alfabetico
Try, 101 TSL, 82 Tunelizaci6n, 172

UNIX, 118 updateArray(),230 updateAsciiStream(), 230 updateBigDecimal(),230 updateBinaryStream(),230 updateBit(),230 updateBlob(),230 updateBoolean(), 230 updateBytes(),230 updatecharacterstream(), 230 updateClob(), 230 updateDate(),230 updateDouble(), 230 updateFloat(),230 updateInt(), 230 updateInt(),230 updateLongo, 230 updateNull(),230 updateobject(), 230 updateobject(), 230 updateRef(),230 updateRow(),230 updateshort (), 230 updatestring(), 230 updateTime(),230 updateTimes tamp(), 230 URI, 70

WAR, 73, 445 WebLogic, 71 While, 102 Windows, 46 WML, 60

XDataSource, 237 XML definicibn, 68 transformaci6n de, 68 y las bases de datos, 68

VARBINARY, 221 VARCHAR, 221 Variables de directiva, 595 Void, 113

S-ar putea să vă placă și