Programacion Java Server J2ee

  • Author / Uploaded
  • Wrox
  • 0 0 0
  • Like this paper and download? You can publish your own PDF file online for free in a few minutes! Sign Up
File loading please wait...
Citation preview

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,'~edricha 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 [email protected].

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 [email protected].

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 [email protected]. 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 [email protected].

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 [email protected].

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.

37

Introduccion

J2EE Edici6n 1.3 .......................................................................................................................................... 37 iQuk ha cambiado en esta edicion del libro? ....................................................................................... 38 ?A quiin va dirigido este libro? ................................................................................................................

38

tCubles son 10s contenidos de este libro? ...............................................................................................

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

.

45

..

46

Capitulo 1 Plataforma JZEE Programac~onpara empresas .....................................................................................................................

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

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

.

Capitulo 3 Procesamiento distribuido con RMI

119

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

................................................................................................................... RMI. cortafuegos y H T T P ....................................................................................................................... Sockets de adaptaci6n y SSL

160

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 .................................................................................................... Escribir programas con RMI-HOP ...............................................................................................176 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

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

El paquete javax.sql

232

234 La interfaz javax.sql.DataSource ......................................................................................................... 234 El mCtodo getconnection() ......................................................................................................... 234 235 El metodo getLoginTimeout() ..................................................................................................... El metodo setLoginTimeout() ...............................................................................................235 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 Resewa de conexiones con el paquete javax.sq1 ...........................................................................243 La interfaz javax.sql.ConnectionPoolDataSource...................................................................... 244 244 La interfaz javax.sql.PooledConnection ...................................................................................... 245 La interfaz javax.sql.ConnectionEventListener.......................................................................... La clase javax.sq1.ConnectionEvent ............................................................................................. 245 Implementaci6n de reservas de conexi6n .............................................................................245

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

246 Transacciones distribuidas i Q d es una transacci6n? .................................................................................................................... 246 247 Antecedentes ........................................................................................................................................ Procesamiento de transacciones - Conceptos ...........................................................................248 248 Demarcaci6n de transacciones ..................................................................................................... Contexto de transacciones y propagaci6n .............................................................................249 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

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

288

.

Capitulo 6 Programacion de servlets

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

Analisis del API Java 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

349

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

Protocolo sin estado y sesiones

350

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

415

..................................................................................................................................... Filtro de rnuestra .................................................................................................................................. i Q u i es u n filtro?

416

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

.

Capitulo 10 Fundamentos y arquitectura de JSP

........................................................................................................................ Presentaci6n de JSP ................................................................................................................................ Los aspectos pricticos ............................................................................................................................. La especificaci6n JSP 1.2

468

471 471 472

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 ............................................................................................................................... 488 ........................................................................................................................ 490 ..................................................................................................................492 .................................................................................................................................. 495 ................................................................................................................................. 495 ..........................................................................................................................500 .................................................................................................................................. 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 ....................................................................................................................... La pagina JSP de procesamiento de solicitudes ...............................................................................512 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 11 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

599

............................................................... Ejemplos de bibliotecas de etiquetas existentes ..................................................................................... Introducci6n de la Biblioteca de Etiquetas Estindar JSP (JSPTL) .................................................... Ventajas de utilizar bibliotecas de etiquetas personalizadas

600 601

602 602 Obtener JSPTL .................................................................................................................................... r y. j ; c l a s s JNDISearzhAttrs {

/ / 1 m p l e r r t e r ~ t a c i ; ~ rd~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 ' ; 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";

public public

statlc static

String String

public

static

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

JNDI

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

=

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 - i n gijrl = s r . g e t N a m e ( ) + ", " + MY-SEARCHBASE;

i f

" + dn);

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

is

Attributes

M Y ATTKS);

(ar

==

ar

null )

=

ctx.getAttributes (dn,

{

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

1 else for

t

the

specified

attributes\nM);

{

( i n t i =O;i capplet (:debase=". "

/ t, t 11, i ?

~ : ~ : ~ d e = " C a l l b a c l . : A p p lcel 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

(

I

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:

I

Entidad

Implementaci6n

Implementado como

Activador

java. rmi. activation-Activator

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

Grupode activaci6n

java.rmi.activation.ActivationGroup

Claseabstracta.

Monitor de activaci6n

j a v a . r m i . activation.ActivationMonitor

Interfaz.

Sistemade activaci6n

java.rmi.activation.ActivationSystem

Interfaz.

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.

o

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 ode 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 .e r 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.

O

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

0 El objeto debe incluir un constructor especial que tome dos argumentos, su identificador de

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.

.

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

HelloServel-

e s t e r ~ d sActivatable

implenier~ts H e l l o I n t e r f a c e

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

publiz

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;

~ , ~ ~ b cll ia sc s

RegisterIt

!

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 "); 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: - P j - r ~ ~ . : : e , : ' ~ r i t ! ; . p ~ l i r 2 y = r ~ ~ t? .i p~r t. el ir ci y -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

j

.

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

Ll 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

puhlic

impl.ements H e l l o I n t e r f a c e

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

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

&

data)

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.",

)

,

) ) ;

1

public Strir,g ~ a y H e l l ~ !ttlrk?ws ) RemoteExcey;tinr~{ return "Hello Igi'~-ld,the current system timr i-" i

t

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 S y s t e r r ~ . s e t S e c u r i t y M a r l a g e r( 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( ) ;

I

El cliente inicia la nueva JVM en el servidor debido a la activaci6n lenta (activaci6n la primera vez que el metodo es invocado): i m p f ~ r tj ava. rml. * ; public class HelloClient

{

public statiz void main(Strir1g args[l) 1 if (arqs.length < 1 ) { System.out.println ("IJsaqe: java HelloClient "); 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)iolH ly e as.2jb oinltnirp. tu om e.tsy Sjb o( sayHe110 ( ) ) ; System.out .prir~tln }

catch (Exception e) { System.out .println ("HelloClier~texception: " e.printStackTrace ( ) ;

t

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

-I

Opciones

--

---

Nombre de lmagen

--

--

Nombre de usuarlo

-

CPU

Uso de

...

A

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

3rocesos: 23

Uso de CPU: 13%

[xi&ETl

:

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 ( R e m o t e 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~ejoranotable 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

Socket d e servidor

Socket d e cliente

Rcgistro RMI

Abre un socket d e servidor (puerto por dcfecto 1099) y espera solicitudes de:

Utiliza un socket de cliente para establecer una conexi6n a un objeto servidor justo despues de haberse registrado.

U Servidores para asociar, reasociar,

y desasociar in~plementacionesde 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 ) .

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

N o s e utiliza.

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.

9

Capitulo 3

\

/'

,

-1 ,~Naming.bind('HelloSe~eV,obj;) \ >.

Objeto

'

,remOto I' _ , , '

,

1';

i

! I

Socket de S e ~ d 0 Ir

Socket de servidor

t

9I

i

Devuelve el stub

1

Socket de cliente

1

13

. Cl~ente 1 - - Invocac~onde metodo

-

-

.

-

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

;

1

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 a cutilizadapara 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 SSLContest ctx = SSLContext. getIr~stance( " T L S " ); 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);

1

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

" ) ;

1 try{ HellaIntetfacr

1

nb]

= ! H e l l o I r ~ t e r f a c e ) E l a m i n gl .u o k u p (

"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 ) ; S y s t e r n . o u t . p r l n t l r ~ i o b j. s a y H e l l o ( ) ) ; catch (Exception e ) 4 System.out.println(e);

I

El archivo ssl .policy que utilizarnos aqui es en realidad el misrno que utilizarnos en 10s ejemplos an teriores: grant [ permission

I

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): r n i i r e < ~ i . s t r y- J - D j a v a . 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 E s ] a v a . r r n i . s ~ r v e r . c ~ ~ ~ e k a i l ~ = f i 1 r : / / r ( -l H BOOMOE +~/ 1 3 h O ? / S - C L / R?qi~trrIt

Recuerde instalar con cuidado JSEE. Ponga 10s archivos jar en su localizaci6n \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~acende claves a utilizar utilizando la propiedad JSSE j a v a x . net. ssl . truststore. Este es el~lmacknde 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:



Capitulo 3 < p a r a m n a m e = " s c r i p t a b l e n VALUE="false">

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:

-._.

.

1

A

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

I

~-0)arasecuritypolic~C:I~roJaaSe~e~ChO3ISSL'r~~lpolic~

Finalmente, debemos obtener u n resultado similar al siguiente:

Hello World, Me current system lime 15Wed 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=. 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.

o Utilizar el script java-rmi-cgi (o servlet) es una gran trampa de seguridad en el servidor. El script redirige cualquier solicitud entrante a cualquier puerto, circunvalando por completo el cortafuegos. 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

JRMP

Cl~enteRMI

Se~dorRMl

(solo Java)

Cl~enteCORBA (cualquler lenguaje)

*

C

llOP

(solo Java)

'

SeNldor CORBA

1

(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~~steobjeto 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 ~roblemascon 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.

0

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 ejoe bc 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();

1

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

0

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.

0 Genere I D L con r m i c - i d 1 para clientes CORBA (si a nuestro objeto tambikn van a acceder

clientes CORBA). 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 rj~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);

1

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: j ava . rmi. RemoteException; java. rmi .server.UnicastRemoteObject; java.uti1. Date; javax.rmi.PortableRemoteObject; class Helloserver implements HelloInterface

[

public void Helloserver() throws RemoteException

[

import import import import public

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 ) {]

I

I

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 ( ) ;

I

;

#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.ej 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

Instancia el O R B

O

Instancia el sirviente y lo conecta a1 O R B

O

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

O

-i

%JAVA-H O M E % \ l i b - t d

client

IDL:

-fclient

HelloInterface.id1

Escriba la clase cliente. ~ s t puede a ser un applet o una simple clase Java.

import import

o r g . omg. C o s N a n l i n g . org.omg.CORBA.*;

*;

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 ORB o r b = O R B . i r ~ i (t a r g s , n u l l ) ;

/ / 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) ); //

1

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

0 N o obedece a la propagation de contextos de transaction y seguridad en las JVM distribuidas (de

hecho, no obedece a la propagacion de context0 en absoluto)

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 pSon ) . 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~coen 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).

java.rmi.server .codebase

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.

java.rmi.server .hos tname

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.

java.rmi.server logcalls

.

1.1

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)

Description

java. rmi. server .randomIDs

1.1.8

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.

f

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 sut!.

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)

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

s u n . rrni. s e r v e r

.a c t i v a t i o n .debugExec

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

.

Descripcidn

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

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.

-

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

Procesamiento distribuido con RMI Propiedad

Introducida primera vez (versi6n)

Descripcidn

s u n . rrni. t r a n s p o r t .connectlonTimeout

1.1.6

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 acceso a bases de datos mis comunes abstravendo 10s detalles es~ecificosde vendedor de una determinada 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.

.

.

O

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.

O

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

O

Caracteristicas avanzadas del API JDBC, incluido listas de resultados desplazables y actualizaciones de lotes

O

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

O Transacciones distribuidas (c6mo el paquete j a v a x . sql, junto con el API Java Transaction,

habilita las transacciones distribuidas)

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

Apl1cac16nJava

Fuente de

1

datOs

i

1

-

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 I

I

I I

'

API JDBC

-1

-

1

;Drlver JDBC (delwdedor

API '

I I

-

I I

\

I

I

v

especlflco

datos

-

I

7 --

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

Aplicacldn

I

Java

I

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

Los drivers Tipo 4 son una alternativa Java puro a 10s drivers Tipo 2:

Apl~cacion Java

\

JDBC

1 Drwer 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 puedeencontrarloen%~ 2 ~ ~ ~ ~ 0 ~ ~ % \ l i b \ ~ l o u d s c a p e \ ~ l oj aurd. s c a p e . 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

Descripci6n

java.sql.DriverManager

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

Descripcion

java.sql.Array

Esta interfaz proporciona una abstracci6n ARRAY de lenguaje Java, una coleccion de tipos de datos SQL.

j ava. sql. Blob

Esta interfaz proporciona una abstraccion de lenguaje Java de SQL tipo BLOB.

j ava .sql .Clob

Esta interfaz proporciona una abstraccion de lenguaje Java de SQL tipo CLOB.

j ava. sql. Date

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.

java.sql.Time

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.

java.sql.Timestamp

Esta clase porpociona una abstraccion de lenguaje Java de SQLtipo~lME,yamplialaclase j ava .util .Date.

java.sql.Ref

Esta clase proporciona una abstraccion de lenguaje Java de S Q L tip0 REF.

java.sql.Struct

Esta interfaz proporciona una abstraccion de lenguaje Java de tipos estructurados SQL.

j ava. sql .Types

Esta clase alberga un conjunto de numero enteros, cada uno de ellos se corresponde con un tip0 SQL.

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

Descripci6n

java.sq1.DatabaseMetadata

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

Descripci6n

java.sql.Resu1tSetMetaData

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.

java.sql.ParameterMetadata

Esta interfaz le permite acceder a 10s tipos de parimetros de bases de datos en instrucciones preparadas.

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 java.sql.Connection, java.sql.Statement,

y java .sql .~ e s u tl ~ e paraaccederalas t advertencias. j ava .sql .BatchUpdateException

~ 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

o

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

Protocolo: En la sintaxis anterior, jdbc es el protocolo. ~ s t es e el h i c o protocolo permitido en JDBC.

0

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

getMetaData ( )

Apoyo de transacciones

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

Estado de conexion y cierre Configurar diversas propiedades, limpiar recuperar cualquier advertencia genera a

isclosed () close () setReadOnly ( ) isReadOnly ( ) clearwarnings () getwarnings ( )

Convertir strings SQL en SQL especifico de base de datos y configurar vistas y tipos definidos por el usuario

nativeSQL ( ) setcatalog () getcatalog () setTypeMap ( ) qetTvPeMaP ( )

valOresd

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

+

protocol);

1

I

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 ( ) ; =

) ) ;

1

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 %J2EE~HOME%\lib\cloudscape(o%J2EE%J2EE_HOMEg\lib\cloudscape(o%J2EE_HOME%\HOME%\1ib\~ystem). 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 C r e a t e M o v i e T a b l e s . E l r n C t o d o c r e a t e ~ a b l e( ) obtieneunaconexi6nde~~river~anager.Para 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 blee 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;

//

Esta clase requiere un archivo d e texto Llamado catalog.txt contenga / / 10s datos d e entrada. public class CreateMovieTables

que

{

static String driver = "COM.cloudscape.core.JDBCDri~er"; static String url = "jdbc:cloudscape:"; String title, leadActor, Connection connection; Statement statement;

leadActress, type, dateOfRelease;

public void initialize ( ) Class.forName(driver);

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

}

1

statement.executeUpdate(sq1String); statement.close(); while (br.readLine() ! = null); / / This reads the termination line

catch (IOException e ) { e.printStackTrace ( ) ;

I finally { br.close0;

I I public void close ( ) throws SQLException 1 try I connection. close ( ) ; ) catch (SQLException e ) { throw e;

t

I

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 ( ) ;

1

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

getAsciiStream()

getBigDecimal()

getBinaryStream

getBlob ( )

getBoolean ( )

9etByte ()

getBytes

getcharacter Stream0

getClob

getDate ( )

getDouble ( )

GetFloat

getInt ()

getLon9 ( )

getobje c t ()

getshort ()

getstring ()

getTime ( )

getRef

()

()

getTimestamp ( )

()

getURL ( )

()

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

ResultSet

rs

=

=

"SELECT CATALOG.TITLE, CATALOG.LEAD ACTOR, "CATALOG. LEAD ACTRESS, CATALOG. TYPE, " + "CATALOG.RELEASE DATE FROM CATALOG";

"+

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"));

1

I

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

statement.executeQuery(sq1String);

ResultSetMetaData metaData int nocolumns

=

* FROM CATALOG";

=

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:

o

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

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 . Dentro de la etiqueta , fijese en las tres entradas para el nombre del sewlet, el nombre de presentacih del sewlet, y la clase cualificada Java. La etiqueta 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 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

Los principios bisicos de HTTP: 10s diferentes tipos de solicitudes y detalles del paradigma de solicitudes y respuestas H T T P

0

Los servlets Java, las paginas JSP y 10s descriptores de despliegue

0

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

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.

0

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.

O

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.

0

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

o

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:

0

Clases e interfaces para la irnplernentacidn de sewlets, incluido las excepciones de sewlet

O Configuracidn de sewlets O

El ciclo de vida de 10s sewlets

0

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

mterfaz Sewietbntext

I I

t

t StrearnSal~da StreamSalida

StrearnEntrada StreamEntrada

I

+

mterfaz LanzadorSolicitud

1

~

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

lnterfaz escuchante de eventos Escuchantede asociacion

intern

de sesion http -

--

I

~nterfaz RespuestaServletHttp

o..*

--

Cookle clonable Cookie

ava lo Ser~al~zable

va lo Ser~al~zable

Sol~c~tudServleHtt

A~nterfaz Sesi6nHttp -

1

1

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 arnplien las clases del paquete 1a "a: . s*r 1.1 * t , tendra' que rnantener algunas de las asociaciones. 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?

O

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.

O

iC6mo leemos solicitudes HTTP y c6mo generamos respuestas HTTP?

O

i C 6 m o tratamos las excepciones en 10s senlets?

0

iC6mo pueden 10s sewlets interactuar con su entorno?

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

j avax. s e r v l e t . S e r v l e t C o r ~ f i g

Excepciones servlet

javax.servlet.ServletExceptior~

Solicitudes y respuestas

javax.servlet.http.HttpServ1etRequest

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

javax.serv1et.RequestDispatcher

Filtrado

javax. servlet. Filter

( * )

javax. servlet. Filterchain javax. servlet. FilterCorifig

Varios

( + )

it)

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 eys H 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 re 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.

0

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.

0

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

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 metodos ~ O X X X( ) . Incluso en esos casos, debe considerar incluir una llamada a s u p e r . s e r v i c e ( ) en 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

0

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 rpv 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. Esta clase utiliza el m ~ t o d o g e t ~ r o t o (c) ode~ 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 consecuentemente 10s metodos ~ O X X X( ) correspondientes (except0 10s de 10s metodos TRACE y OPTIONS).

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 ecr~v l e t o su s u b c l a s e ~ t t pes 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 entre las diversas responsabilidades de un contenedor, la gestion del ciclo de vida es la mbs .-es 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

-1

1

Instanclac16nbasada en una sollcltud o en el

7 -

+

lnstanc~ado

arranque del contenedor

-

-

--

-

Fallo en ln~c~ac~on

L~berar

referenc~a

De vuelta a revlslon en caso d

I

indisponibilidad temporal

1 Sol~citud(es)HlTP de

1

I

Hilo de final

Fallo temporal o permanente

1

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 ~o U 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

HTrP 1

---4 ---

4 Sewlet

lnvocar m e t o d o l n l-t ( ) -. - -

*Destmar sollcltud a hllo

4

Ejecutar

lnvocar metodoservlce

I Sol~c~tud HTrP 2

1

-----,

Destlnar sollcltud a hllo & --

C~erre

'Ejecutar rews~on

Ejecutar revlslon 10s h~losactlvos

/t-

HTrP 1

--

--

-

-

F~nal~zar reselva de h~los -

Y

*.

/

ocar metododestro

b

Respuesta

HTrP 2

*i Servlet destruido y la YI

-

C~erredel 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:

.java,

, ' / 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

=

10;

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

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("" )

;

out .println I" FreakServlet: State History" ) ; o u t .printlr~( " g i n a m

O p e r a t i n g S y s t e m : ~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

d

3onterltc: ofWph App - -

-

Q UWEB-INF Q d classes

0 TechSupporlSen4et.class

0-

d lib

0 techsupp.html

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 MUbe 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 In thrs WAA file. For each oilheae, indltate the b e ofresourcs rearnred, and h m f h e aulhenllcalron ofresource users vd~lbe handled (apoltcation-managedor contarnsr-managed). OptionalC, you can define lf Me resource IS sharable and prwlde a descnpZonfor it.

Pro~ramacionde 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~eFiles

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-~ n r ~pnsnmw

.- .- --

Load at anytlme -

-

.... .

ni=?--

2

- -- .

-

-

I

I

I

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

0%

9 O JMS

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%\ b i n . Conecte ahora la herramienta de despliegue a1 servidor activo, seleccionando ~ d Sd 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

I

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 ryt haga clic en N e x t (Siguiente):

342

Proeramacion de servlets

References

Ref--Tvpe Resource

--

1

Referenced BY Web ~ p p

I Reference Name

I

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 TechSupport h:as 0 ejbs, 1web components lo deploy Deploying Ejbs Processing be:ans ... Making client JI4Rs ... Making server. JARS ... . . ,. . ..- .. . -. -. .. .. . Contact the wea sewer ana asK r lo run: c:yzsa~eel.;r~nreposaolyrob 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

E m d Ixander@sunrydale corn

I

S o b a r e MicrosohAccess

Phone

3

1

operahng System: windows 2000 Pro

Problem Descri~tion Cannor converc database

flied

A

S~bmd Request

A1 enviar este forniulario, el navegador debe generar la siguiente respuesta:

wctha

Ed~clclm

Yer

Favortor

Herramentar

Ayda

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 enumber has been received Request Reference 1 Please note h s number for fuh~rereferences. n hours Your request wdl be attended to w ~ h 24

Ahstrator Techsupport team

=I

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 loe H t ttpServlet. O

La c l a s e ~ t t p ~ e r vaemt p l i a ~ e n e r i c s e r v l e yt proporciona funcionalidad especifica HTTP adicional.

3

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~ramacionde servlets 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.

0

Utilizamos descriptores de despliegue para especificar 10s parimetros de inicializaci6n. Esto nos ayuda a evitar la codificaci6n de tales parimetros dentro de 10s servlets.

0

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~itudprocedente 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.

0

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.

o Campos de formulario ocultos 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

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.

0

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:

  • User Prefs


  • Capitulo 7 < l i > < a href="http://www.myserver.com/servlet/tsEntry;uid=joe"> Time Sheets < 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 .


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). Los parimet~osde consulta son pares valor-nornbre separados por "&", mientras que el parimetro de ruta 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 :

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 . s e t M a x A g e ( 6 0 * 6 0 ); / / 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("/");

/ / 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 );

hora

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 pes 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 nproporciona 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,pararepresentareventosasociados 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 os 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 ocomo 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 obtenidaa travks del m C t o d o g e t ~ e s s i o n( ) del o b j e t o ~ t t p S e r v l e t ~ e q u e s t . 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~rimirla informaci6n anterior. A ~ a r t ede 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:

1

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 Maximum 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~ (" < a href=\" 'I + 1ifeCycleURL + " ?action=invalidate\">") ; out .println ( I 1Invalidate the session") ; out .print ( " a r > < a href=\"" + 1ifeCycleURL + ' I \ " > " ) : out .println ("Reload this page") ; out. println(""); out. close ( ) ;

1

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: Remove"); out .println ("") out.println("") ; out.println(""); 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 ("
Narne: V a l u e : ") ; out.println(att value);

) ;

n u t . p r i n t l n ( " < / b o d y > < / h t m l > " ); out.close();

I

Este servlet le permite introducir pares valor-nombre en una forma HTML y aiiadir estos datos a la sesi6n. Tan~biknle 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:

1

Enter name and value of aa atiribute

Name:

7 Value:-]

r Remove

Update

I

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

O

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 essi 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 H t t p ~ e s s i o n B i n d i n g E v e n t p r o p o r c i o n a a c c e s o al a ~t tp s e s s i o n

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 ~n ei sr texcept0 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 ndel 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( ) ;

res)

int itemcount = 0; ArrayList cart = (ArrayList) session.getAttribute ("carttt1; if (cart ! = null) { itemcount = cart. size ( ) ; 1

res. setContentType ( " t e x t / h t m l V ; Printwriter out = res.getWriter0; out.println("Simple Shopping Cart " + "Example"l; out.println(""); out .println ("") ; out .println ("
") ; out.println("WROX Book Store
"); out .println ("

You've " + itemCount + " items in your cart.

" ) out .print ("") ; o u t .println (""); out.prir~tlr~("");

;

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 (""); out.println(""i; out .println ("") ; out .println ("" ) ; out .println ("" ) out .println ("
Add t o Cart ") ; out .println ("Itern 1: " t " Begining Java2 - JDK 1.4 Version
") ; out.println("Itern 2: " t " Professional Java XML
") ; out .println ("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 ( "
") ; out.println("" ) ; out .prir~tlr~("") ; 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 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 upara 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. 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 ~t i s 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;

public class ShoppingCart

extends HttpServlet

I

public void doPost

(HttpServletRequest req, HttpServletResponse throws ServletException, IOExceptlon ( HttpSession session = req.getSession(true); ArrayList

cart

=

res)

(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(""); out .println ("Shopping Cart Contents") ; out .println("") ; out .println ("") ; o u t .println ("Items currently in your cart") ; out.println(""); Iterator iterator = cart. iterator ( ) ; while (iterator.hasNext ( ) ) { out .println ("

" + iterator.next ( )

t

"

");

1

out.print("

Back to the shop

");

Recuerda que cuando un formulario contiene mliltiples casillas de verificaci6n con el mismo nombre, el parimetro puede tener mliltiples valores. Por lo tanto, el mCtodo get ~ a r a m e t e r ~ a l u e( )s es utilizado 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 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">

l.O

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

pfiblicarnente accesible. Exarninernos cada uno de ellos sucesivarnente.

absolute, apuntando a un TLD

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

/

I

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 .*;

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;

extends

Tagsupport

{

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

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

".
"); .getName ( ) t t "

"); 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:

helloAttrib

tagext.AttribHelloTag JSP Simple example with attributes

name true true

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:

Simple tag with

an attribute

This is static output.



Proporcione ahora un valor atributo en el periodo de ejecuci6n: < % String

readerName

=

request. getparameter ("reader"); % >

< % if

(readerName ! = null) [

%>

Si tenernos un valor con el que podernos trabajar: Thank you. You told me your name


/>

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 reader parameter:
remember I trusted you with my fully-qualified class name!!

This is static output again.



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:

-

-.

-!I

-

l.

, - - .,.

. ..

Archivo

I -

Edk16n Ver

I

' -

-.

Favortos

o I

I ~

9a-, @kqueda

-

,

--

-l

~

.~

- -

Herramlentas -

-

---

Ayuda

x

~

.. -

(

- ... ... ..

-

BFavoritos

H e h Rod My raame is tc~gext.AttnbHelloTagand it k Sat Aug I6 I7:20:59 BS'T2001

III

I&

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

II local manet

ist to

A

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: , ., . . , 8 4

Archwo

II

Edicion

Ver

Favorites -

-

1

Herramlentas

I

Ayuda

,

'

-

-. --

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. rMy name is tagext.AttribHelloTag and it's Sat Aug 18 17:23:41 Bfl2001 Thls is static output agah Listo

r mi

-

--

intranet

v I J -- -

//

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 dhay , 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: a1 elemento relevante < t a g > en elTLD

0

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

variable-class?,

Examinernos sucesivamente cada sub-elemento:

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 "deporteVy la etiquetaes invocadaasi: 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 .

O

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:

helloVars tagext.VarHelloTag JSP Simple example w i t h scripting variables

narne

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 java.lar~g.Strir~g

className j ava. larig. S t r i r ~ g < / v a r i a b l e - c l a s s >

date java.util.Date

name truei/required>

truei/rte~prva1ue>

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

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>

< t i t l e > B o n j our: ,:/head>

Tag with scripting variables

.'body>

HTML



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

> +>Plus d e HTML.



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 .

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




Para implementarlo, primero necesitaremos ahadir un metodo aVarHe 1101t 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

I

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~ameconte x t ) es tambien trivial ya que simplemente implementamos un nuevo mktodo: public

I

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");

I

"

t

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

public Persc?nalInfo(String nationality, this. nationality = nationality; this.city = city;

String

city)

1

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:

nameInfo

tagext.NameIr~foTag 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 x it r l t e r f a c e

java.lar~g.Strir~g



I

HTML.



< % java.uti1 .Random rand = new j ava.uti1 .Random() ; %>

Hello . You're entry in my list. < % if (rand.nextInt(3) ! = 0 ) { % >

Nationality: City:




More 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 Fe entry 0 in my list. Nafionality: Australian City: London Hello k a b e h . You 're entry 1 in my list. Hello Bob. You 're entry 2 in my list. NaiionaLi~:Australian City: a d m y Hello Jens. You 're entry 3 in my list. More HTML

I

& ist to

rr[@

Ll local intranet

A

Intente carnbiar el ejernplo para trasladar la etiqueta 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 tcontiene 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 aest oespecificada 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. 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 ny.aContiene 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 a recurso que debe ser objeto ficticio l l a r n a d o t h i s ~ u s t ~ e ~ tuelrl~~nfv o c a t i o n p a r sirnularun 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.';

public class TryCatchFinallyIterationTag

private List names; private int index; private StringBuffer output

=

extends Tagsupport implements IterationTag, TryCatchFinally

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: 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 ~= new setloopvariables ( ) ;

Object ( ) ;

El valor de retorno es el rnisrno que el de una etiqueta normal, no iterativo: return

EVAL BODY INCLUDE;

1

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

I

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 : ( 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 BODY AGAIN;

if

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

narnes.qet(index).toString()) ;

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

I n t e g e r ( i n d e x )) ;

I

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 ) ; p a g e C o n t e x t . g e t o u t ( ) . p r l r ~ t l r (t " < f o r ~ t c o l o r = \ " r e d \ " > " + " 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 ")");

("

+

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

1

Este metodo comprueba que nuestro recurso deseado ha sido liberado sin problema: private i f

1

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" ) ;

I

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> r ~ T a g < / t a g - c l a s s > narnes~/name> crequired>t rue true

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) d~ e ~ r ~ ~ a t c h ~ i nt ear al tl iyo ~n ~ a ~ l a n z a 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>

[ ) ;

I

cb,.dy> 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>

.

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

I

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.

u Utilizar contenido de plantilla para generar salida HTML ~ 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 oor B 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

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

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.

0

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.

LI

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 ,

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

y

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 sEsto ). 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

0

Los autores de piginas disehan piginas Web

O

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.

0

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.

0 JRun 3.x Enterprise Server de Allaire; JRun ofrece algunas etiquetas 6tiles y sencillas para

aplicaciones de ernpresa, que simplifica en gran rnedida el desarrollo de aplicaciones JSP. Vkase http://www.allaire.con7/products/jrun. 0

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.

O JSPTL es lanzada a travks del Jakarta Taglibs Project y animamos a1 lector a conocer algo mis

sobre este proyecto en http://jakarta.apache.org/taglibs/index.html.

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

Reduce la cantidad de c6digo de scriptlet en plginas JSP, de una rnanera unificada.

0

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

Iteration

0

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 ~rornetedoresAPI 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 "". 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


< t i t l e > A n e x a m p l e JSPTL f o r E a c h " >

< j r: forEach var="myItem" items=" " > < ! - other HTML markup to be looped over for each item ~n rnyList ->

< / fnd : if> < / j r: forEach>

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.S t r i n g 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:

€jx:sec var="count" value="$~tacus .countn/> c/]x:if>

€/table> €p>There are El ernpleado es pensionista. < / j x :when>

El empleado es de rnediana edad.

El emepleadono es demediana edadnipensionista. < / j x : othewise>

Capitulo 12

I

-

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

La etiqueta when, utilizado s61o en el contexto de una etiqueta de elecci6n progenitor.

otherwise

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

II

I

Beware

Access

- API and Tags may/will change

sunnort develonment comments to SRO52 EG

JSPTL Examples Introduction Iterators Conditionals EL Support

&

II

Conditional Tags Examples

Mutually Excluslve Condlclonal Executlonc/h3>

--

11

WSA:blue Canada: red Ochers:grecn c~x:forEachvsr="customer" item*-"$cuscorrprs">

cjx: when cest="Scuscomer address. country == ' USA' ">

Click Here!
registered first, within the same session. Click Here!
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, Click Here! < 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, 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, C1ick H e r e ! < / a >

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

I

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 p tn 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"

I

;

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

( )

{ )

1

/ / 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,r e s p o n s e ) ;

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,

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

I

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 ~ ajsp") 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 j s. 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 . p u b l i c v o i d d o L o g i r ~ U s e r (H t t p S e r v l e t R e q u e s t r e q u e s t , 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 $ >



Capitulo 12 value='

) )

%>'

Region of Origin:
(Please choose one)

< % = aRegion %>

< / td> Company Name:


Your Role:

< % = aRole %>

Main Hobby:

Favorite Web Site URL: .

name, value, required, disabled, readonly, nurnberOfColumns, description, tabIndex, accessKey, onFocus, onLoseFocus, onselect, onchange

Equivalente al elemento HTML .

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 ( ) .

. . .>.

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.

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~pten 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 . 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 y 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 ~ a v a ~ c reni ~ 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.

P

list

radioButton

checkbox

id, items, itemType, name, allowsMultiple-Selections, disabled, tabIndex, onFocus, onLoseFocus, onchange, visibleRows

Una etiqueta de lista que facilitala generac16n de HTML < se1ect> con etiquetas especificados e integrados. Itera elementos de tipo itemType, permitiendo la creac16n de una lista de elementos HTLM .

name, value, label, valueAndLabe1, required, checked, disabled, tabIndex, onFocus, onLoseFocus, onchange

Equivalente a un elemento .

. . .>.

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.

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.

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 "

%>

< % @ t a g l i bu r l = " / h t r n l W p r e f i x = " h t m l " % >

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"> < t d > U s e r Name: < / t d > < h t r n l : t e x t I n p u t name="usernarne" value="

%>"

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 ~ . + " % >

< i l P r , : r e s o i ~ r c e B u r ~ d l er,ame="writirigjsps.registratior~.Registratinr~Resourzes"> % D i s p l a y t h e g r e e t i n g m e s s a g e , i r ~ s e r ~ i r t tqh 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 >

<

p>Thanks

for

reqlsterlnq l'br>

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

Many t h a n k s , < b r >
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
.: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". © W r ~ xP r e s s L t d , 2001

the

applications.

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

2

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.

v m w . w r ~ xcorn .

We try our best to ensure your ~rformationis 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 es 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 l l a r n a r s e ~ y ~ p p ~ e s o u r cSin 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 lot-

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

()

. En el caso

0 El lote raiz de recursos, cuyo nornbre es el nornbre base elegido.

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~blea1 lugar

MyAppResources

lote de recursos Baselraiz

lote de local~smo porDefecto

lotes de local~srno Deseado

El mas sens~bleal 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

Descripci6n

locale

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.

useClientLocale

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.

string name

El nombre de la ropiedad en el lote de recursos cuyo valor debe ser Bevuelto.

alt

Unvalor alternativo para ser utilizado si la pro iedad especificada no pudiera ser encontrada en el Pore de recursos. Espec~ficarun 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~rg .

message

name

El nombre de la propiedad del lote de recursos, cuyo valor debe ser devuelto.

alt

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.

B

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 bajo la etiqueta progenitor de mensaje. Por lo que el siguiente mensaje

Escribir aplicaciones JSP con bibliotecas de etiquetas Atributo Podria escribirse utilizando la etiqueta :

El valor del argumento.

value

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 > 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 ~o s hacerrios 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

a

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

2

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

II

IIII

-

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.

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:

Registration Errors

Sorry, t h a t u s e r n a m e w a s a l r e a d y and c h o o s e

another

username.

c/html>

Los resultados de intentar registrarse como miembro ya existente son 10s que mostramos en la siguiente captura de pantalla:

I

Arch~vo Edicih

Ver

-

Herramientas

Favorltor

Ayuda

-

. ,m

I& http //localhost 8110WlapTag4pps/reg1stratm~/regForrnSubrn~t L]

~ireccitm

-

-

-

-

-

--

&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

[hmchIfl

FavwRos

Herramlentas

Ayuda

hltp l/localho:t 20001r~pTag4pp.;lr~ilrIrahonllogn

"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

User Profile

< / t r>







ctd>

J F~;,TIS

~L~?-:,im+r

"'"".*'"

~~~~L~~xI!~A~.T

. .:*,*: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 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~OOO2f~erverSld 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 tHttpt p 3 ~ r v I ~ t . s e ~ ~ 1 ~ e ( h ! ~ r ~ 9 e ~ v I ~ c . 1 ~ v n : 8 5 3 ) 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

]dVhN.bervlct.SerVleC~xCCpClo~: An at qt

at

at mc at

at at at

st

st

a at

at at

1

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) sC 0 r ~ . ~ ~ 9 ~ h e . ~ 1 t ~ l ~ ~ . ~ 0 r e . 5 t a n d ~ r d P l p e l i . l n ~ O k c ( J t a n d a r d P l p t l L n c . ] s ~ : + l 2 ) 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 .~jssp. ers





All Reqistered Users /j x:declare id="aUserM type="writinqj sps. r e g i s t r a t i o r ~ ~ u s e r "/ > itd> itd>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 r t se e r u s e r s 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"es 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);

t

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

..-:xrl-ll . ,

Ed&

Ver

Fawitos

Herramientas

Awda

.&.-

=!

,el ;lun="l.O" encnd1ng="lSO-E85~?-1"!:

- c l G E R S number=%'>

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 ) ; r n s g . s e t R e c i p i e r ~ t s(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 ~ Tt y p e . C C , I r ~ t e r n e t A d d r e s s p. a r s e ( " i r ~ f o @ w r ocorn" x. ) ) ; msg.setRecipients (Message.Recipier~tTjipe.BCC, I r ~ t e r n e t A d d r e s s. 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 o0

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

Devuelve el tipo MIME del objeto, incluido cualquier parimetro asociado a 61.

Object getcontent ( )

Devuelve 10s datos. Si e l ~ a t a ~ a n d l ehar 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.

Inputstream getInputStream()

Devuelve un flujo de entrada a1 objeto que esti albergandol representando 10s datos.

Capitulo 13

I

Outputstream getoutputstream()

Devuelve un flujo de salida a1 objeto que esti albergando/ representando 10s datos por lo que el contenido puede ser sobrescrito.

void writeTo outputstream outputs)

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

t e x t / p l a i n . Para rnensajes que son sirnplernente texto ASCII

0

t e x t / h t m l . Para rnensajes que son construidos utilizando texto HTML

0

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

e-mail with

first

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 ~ bej 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: 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 ~ j s r e m . ~ - ~ u t . ~ ~ r i r ~ t l r t ( "c oEmrm~atnedr ( e x i t t o e n d ) " ) ; System.nut . p r i n t l " B " 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 "e e x i t " ) ) break; else i f ( c m d . i n d e x O f [ " d i s p l a y " ) d i s p l a y S i r ~ g l e M e s . s a q e( p o p F o l d e r , e l s e if ( cmd.ir~dex0ft"delete") deleteSirlqleMessage ( popFolder, else { displayMessages(p@pFolder);

String

if )

1 )

.toLi3werCasto

;

{ == 0 ) ( crnrl) ; == D ) ( cmd ) ;

1

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 ,

i r ~ tc l = cmd. i n d e x o f i f ( c l == -11 {

("

") ;

System.out.println("de1ete return;

");

S t r i n g cmd) throws Exception

{

~ n rt n e s s a g e l D Message mess

=

1 n t e g e r . p a r s e I n t ( c r n d . s u b s t r i r ~ 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 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: }

private

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

static

void

[

saveAttachrnent(Fo1der folder,

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;

S t r i n g crnd) t h r o w s E x c e p t i c ' r ~{

< i d > ") ;

I i r ~ tr n e s s a q e I D Message mess

Multipart for

=

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

=

( 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 ) ;

( 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 S t a t e l e s s F i n a r ~ c i a l c u l a t o r < / e jb - n a m e > < h o m e ? f i r ~ 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 < / h o r n e ? 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 ; 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);

System.out . p r i n t l n ("Sales

//

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

for

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 ] ; m a n u f a c t u r e . s e l e c t F o r M a r ~ u f a c t u r e( 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 fabricaci6nWirnprirne 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

factory.clients;

import import import import import Import

java.rmi.RemoteException; j a v a x . ejb. + ; javax. naming. + ; javax.rmi.Fortab1eRemoteObject; java.uti1. Properties; j a v a . io. + ;

import lmport lmport

factory.manufacture.Manufacture; factory.manufacture.Mar~ufactureHome; factory .manage o r d e r s .OpenOrderView;

public

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 .narrow(hand1e.getEJBObject ( ) , Mar.ufactlure.class); 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

factory. clients;

import import import import import import impart

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

import import

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;

public

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

s t a t i c v ~ i dm a i n ( S t r i n g [ ] a r g s )

"DESKOl"; "CHAIROl"; "LAMPO1";

= = =

{

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

ManaqeOrdersHome

=

i r j i t i a l . lookup ("ManageOrdersM);

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 . a d d ( C a l e n d a r . DAY OF YEAP,, 1 4 ); Calendar

calendarSchedulatle

=

C a l e n d a r . g e t I n s t a r ~ c e( ) ; 5 );

caleridarSchedulable.add ( C a l e r ~ d a rDAY . OF YEAR,

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

1, ORDER 2 , PRODUCT 3 , calendarSchedulable.getTime() ) ;

l a c e o r d e r (SALES DIVISION

SALES DIVISION 2 ,

ORDER 2 ,

PRODUCT 1 ,

calendarSchedulable.qetTirne()); ORDER 3 , PRODUCT 2 , calendarOverdue.~~etT~rne ( ) ) ;

SALES DIVISION 1 ,

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 j a v a . larlg. Ir,tGger lO

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 > ebj / O r d e r < / e j h - r e f - r i a m e ;

< / e jb-ref i

c e j h-ref-nameiej b / P r o d u c t < / e j b-ref-name>

Cejh-ref-typeiEntity 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 >

factory.product.PrcrductProduct

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

de

sisterna

de

y c i c l o de

1

public

void

ejbCreate0

public

void

ejbActivate ( )

public

void

ejbpassivate ( )

{

vida

{

1 { ]

~ ~ u b l iv co i d

e j bRemove

public

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 )

void

( )

{ )

[

1

i

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 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 ~inicaclaseque crearemos en 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 af 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

I

Beans de sesion y Iogica de empresa

/ / Propiedades p u b l i c S t r i r l q m a r ~ u fa c t u r e C e 1 1 I L i ; 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 c ~ r r e s ~ o n d i e nct er e a t e ( ) realizada por el cliente sobre la interfaz inicial del bean. Observe que tambikn 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 ~ rt etx ~ t )[ }

A continuaci6n,1os mktodos de empresa: //

Mktodos d e e m p r e s a p u b l i c O p e r ~ O r d e r V i e w[ I

qetOpenOrdors ( )

try ManageOrdersHome homeManaqeOrtjers = getManageOrdersHome i ) ; Manageorders manageorders = homeManaqeOrdtrs. c r e a t e i ) ; r e t u r n manageOrders.qetSched~11ab1eOrders(); )

] }

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 ) ; O r d e r o r d e r = h o m e o r d e r . f i r ~ d E y F r i m a r y K e y( 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 E1 N ) 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 ;

1

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 = p r o d u c t . g e t R o u t i n g I r ~ s t r u c t i o r ~( 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;) C o l l e c t i o n s . s o r t ( r o u t i r ~ q I r i s t r u c t i o r ~;s ) c u r r e n t P o s i t i o n = 0; l a s t P o s i t i o n = r o u t i r ~ q I r ~ s t r u c t i o n s . s i z e) ( - 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 ~( ) ;

t return

( c u r r e r ~ t P o s i t i o n ~ o i dt r a n s f e r ( S t r i n g String con = null;

accountIDFrom, accountIDTo, double

[

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");

amount)

{

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 o r. e a d ( a c c o u n t I D T o , c o r ~;) a c c c . u r , t € r o m . . - e t A r n o u r 1 t ( a a : c i i u r ~ t F r o m . q e t A m a ~ r( t) - a m o u r l t ) ; 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( ) + a m o u n t ) ; 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 , ); S y s t e m . o u t . p r i n t l r ~( " F u r ~ d s t r a n s f e r r e d . " ) ; c o n . cnrnmi t ( ) ;

1 catcl.; try i

(Exception e )

i

con. r o l l b a c k ( ); (Exception r e ) e.printStackTrace0;

1 catch

{I

finally { try i i f ( c o n ! = r 1 1 ~ 1 l 1) 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 aplicacion utilice las sencillas capacidades transaccionales de la clase j ava .sql .Connection.en su lugar, 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 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 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 sin ningun elemento secundario .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;

1

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 : 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 oeln metodo 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

public

//

implements

v o i d someBusinessMethod algunas retrollamadas

...

//

SarnpleSessionA

de

16gica de

empresa,

SessionBean

[

SessionBean

{

{

( )

etc.

i

public

class

SampleSessionB implements

p u b l i c void otherBusinessMethod ( / / o t r a s retrollamadas

I //

...

de

16gica de

empresa,

{

)

etc.

1

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 ( ) ; }

catch (Exception e ) 1 userTransaction. rollback

I

}

catch

(Exception e )

{

( ) ;

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:

I1

Nivel de aislamiento

Problemas evitados

TRANSACTION-READ-UNCOMMITTED

Ninguno

TRANSACTION-READ-COMMITTED

Lectura sucia

TRANSACTION-REPEATABLE-READ

Lectura sucia Lectura no repetible

TRANSACTION-SERIALIZABLE

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 sesion tendrian lugar en la misma transacci6n hasta que invociramos commit 0.Observe que esto s610 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 a irm 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 l 1. o o k u p i " j a v a : c o m p / U s e r T r a r ~ s a c t i o n " ); 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 = ( U s e ~ T r a r ~ s a c t i o ri ~ 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 //

. ..

rnetodos

de

retrollamada,

etc.

I

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

La logica de aplicacion accede a multiples recursos (como dos bases de datos) dentro de una Gnica transaccion

0

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 ~imiticionesde 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.

0

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.

o Control de acceso 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 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 ode 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

0 Exarninar la inforrnaci6n de irnlernentacion del EJB para cornprobar si la identidad es un rniernbro

de un rol a1 que ha sido otorgado el derecho a invocar este rnitodo de empresa O

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 )

0

Poner la informaci6n de identidad y de rol a disposici6n del EJB para cornprobaciones de seguridad exhaustivas

O

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:

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 ~ aq p 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.

teller~/rLo1e-r~ame>

(security-role>

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

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 ( ) ; ( (

1

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

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 a n I r ~ t e r r z e t t r a n s a c t i o n o r ATM withdrawal.

UnmediatdAccess

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

j a v a x . s q l .D a t a S o u r c e paraconexiones JDBC

0

javax.jms.QueueConnectionFactoryyjavax.jms.TopicConnnectionFactorypara conexiones JMS

0

j a v a x . m a i l . S e s s i o n para conexiones JavaMail

0

j a v a n e t . U R L para conexiones URL

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 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 e n v / j d b c / s h i p D B N );

= =

(

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 , un sub-elemento opcional ycuatro sub-elementos obligatorios: , < e j b - r e f - t y p e > , < h o m e > y < r e m o t e > . Elelemento 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 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:

< 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

-: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 . : : / ebj - 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;

p u b l i c c l a s s AccountManagerEJB public SessionContext ctx; public

void

implemerjts

SessionBean

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 ir c~ 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, S u c h A c c o u r ~ t E x c e ~ ~ t i o{ 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

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 . i s C a l l e r I r ~ R o l e ( " A T M " )) { rlew S e c u r i t y E x c e p t i o n ( ) ; && &&

throw

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 ~nr s~ 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;

,

[

1

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:

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 >

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 .

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 >

Account

(security-role-ref>

T t ~ i s r o l e r e f e l - s t ~ a)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 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 .

ATl4i/rc31e-r~an1e>

La referencia de rol se vincula ahora a un rol determinado definido en este descriptor:

j ihwrox.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 ~ < 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 jb - c l a s s i ~Cor~tair1e~~ 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

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



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:

~ s t es e el cddigo para laclase RequestProcessor. Para cada solicitud, actualiza el modelo y decide sobre la siguiente vista de secuencia: package

factory; j ava. t e x t . DateFormat; java.util.Date; javax. s e r v l e t . ServletCor~text;

import import import import import import import import import import import

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 ( ) ;

{

( ( 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 stack!JRL = S c r e e n N a m e s . CHOOSE FOR MANUFACTURE URL; r e t u r n S c r e e n N a m e s . CHOOSE C E L L URL;

if ]

i

1

I

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 ~ (t s 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.MESSAGEA T T R I B , " 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.CELLC H O S E N ) ) { 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.CREATER O U T I N G ) ) 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 =

CREATED))

{

[

req.getPararneter(Screer~Narnes.ROUT1NG S E Q U E N C E P A R A M ) ; String action

=

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:

1 else i f String

action);

(selectedURL.equals(Screer~Narnes.CANCELO R D E R ) ) 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.ORDERT Y P E PARAM) 1 ; try i

1

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 ~ (t s a l e s D i v l s i o r ~ ) , 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 e sR 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. L A C E 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;

)

i

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

/

catch

you

for placing

t h i s order.");

( 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 ( ja v a . t e x t . P a r s e E x c e p t i o n p z ) 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 . " ) ;

return ]

)

S c r e e r ~ N a m e .sM E S S A G E U R L ;

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 S c r e e r ~ N a r v e s S. H I P U R L ;

{

e l s e i f ( s e l e c t e d U R L . e t q u a l s ( S c r e e r ~ N a m e s S. H I F P R O D U C T ) ) { S t r i n g l r ~ a d i r ~ g D , > c=k r e q . g e t P a 1 - a r r ~ e t e r ( S c r e e r ~ N a r n e. S. cH 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

}

prepareMarlajeOrdersReque~t(Strir~g orderType,

void

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 .sO 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 ( S c r e e 1 ~ ~ N ; i r r 1 e s ~ 0 R DAELRT V I E W A T T R I B , 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 .eO~F P E E R 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 ) ;

{

i

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 ' cl 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 " ; ~ ' u b l i c s t a t i c f i r j a l S ~ L - i r ~c hgE A T E ROTJTING = " / c r e a t e r m ~ t i r , q " ; 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 ~ ~ a Sl 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 a Sl t r i n g P L A C E ORDER = laceorde 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 " ; 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 tr e a t e d " ; ~ ~ - 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 " ; p u b l i c ~ t a t i c f i r l a 1 S t r i r ~ qORDER c H O S E N = " / o r d e r c n ~ : , s e n " ; 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 f i r l a 1 S t r i r ~ qS H I P FF:OD!CT = "/ship product";

C H O I C E S IJRL = " / ~ t ~ . ~ l i c jes sp. " ; C R E A T E PRODLlCT IUPL = " / c r e a t e ~ r o d u c t .j s p " ; ? 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. s p " ; 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 = " / m a r ~ u f a c t l ~ r e r o u t ej.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 " ; f i r l a 1 S t r i r ~ qS H I P IJRL = " / s h i p . j s p " ;

-

p u b l i c

s t a t i c

p u b l i c p u b l i c publi.; p u b l 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

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

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 " ; "salesdivision"; "ordernumber";

public public

static static

final final

S t r i r l g SALES DIVISION PARAM S t r i n g ORDER NUMBER PARAM =

public

static

final

S t r i n g MESSAGE ATTRIB = " m e s s a g e " ;

public public

static static

final final

String String

public public

static static

final final

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

public public public public

s s s s

c c c c

final final final final

String Strir,g String String

public

static

final

S t r i n g CELL PARAM

public public

static static

final final

String String

t t t t

a a a a

t t t t

i i i i

PRODUCT I D PARAM = PRODUCT NAME PARAM

ORDER ORDER ORDER ORDER

=

"product id"; " p r o d u c t name";

=

SALES DIV PARAM

=

"sales div";

N U M PARAM = " o r d e r num";

PROD PARAM = " p r o d " ; DUE DATE PARAM = " d u e d a t e " ; =

"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

factory;

import import import import import import

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 ;

import lmport lmport

java.util.Date; java.uti1 .Iterator; 1 ava . u t i l . L i r ~ k e d L i s t ;

import import import import import import import import import import

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 ;

import

factory.order.OrderNotCance1ableException;

javax.serv1et.http.HttpSession; javax.servlet.Serv1etContext;

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

Manageorders rnanageorders; Manufacture manufacture;

private private

S t r i n g currentCellID; S t r i n g currentProductID;

public void i n i t (ServletContext context, t h i s . session = session; this.context = context; rnanageOrders = getMarlageOrdersEJB ( ) ;

HttpSession

session)

{

I

public void try I

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 ) ; . j

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)

1

1

public String getcurrentcell ( ) return currentCellID;

{

I p u b l i c void setCurrentCell(String currentCellID = currentCel1;

currentCel1)

1

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 r n a n a g e O r d e r s . a d d R o u t i r ~ g I r i s t r u c t i o r( ~c u r r e r ~ t P r o d u c t I D , 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

try

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

rnanageOrders.placeOrder(salesDivision, }

I

{

[

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)

orderNurnber, {

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

Product ID

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

i/html>

Puede realizar un pedido:

Archivo

Edici6n

Ver

Favoritos

Herramientas

- -

81

Ayuda -

*

Place an order for a product:

Sales division 101

Order number 111

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

Order number

name="Place0rdert'>

Capitulo 18

,:input

type="submit"

name="Submit"

value="Submit">

i / p>

  < / p >

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~

< t i t l e > W r o x S a m p l e C o d e - Message

t o m a i n rnenu.



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

Archivo

-.

+fit135

Neccih

.

I

.

1 , -

Edicih

Ver

. a .

1

--

I

1 -

I

.

.

I

,

.

m

P

Favo~ 4tos

Mrramientas

- + -ia rn

Ayuda

http://localhost:700~

You are currently mevmg open orders Chl:L, here to mew overdue orders

larder ~ u r n b e r

D -v o i s i i n -

r

w

/

~

l

i

c to Cancel k

8-ehrn to main menu

~ s t es a la vista de pedido atrasado:

Arch~o

c isirx

IIrI

Ed1cb-1 Vsr Favorites Herrermentas Ayuda @ taBbqueda @Favorites Q M u l t ~ ~ ~ d i a

-+-

aI

1 a-a a

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

11

Arnbas versiones de la vista son proporcionadas por manageorders .j sp:

c!~

Capitulo 18

< % @ page < % @ page

import="java.util.Iterator" % > import=" factory .OrderViewM % >

Wrox Sample Code - Manage Orders

Manage Your Orders

You are currer~tly viewing < % = request.getAttribute("order viewn)%>. "> Click here to view ' .

Age This Year:
Actual Age: Pensioner This Year:
Region of Origin:
Company Name:
Your Role:

< / td>
Main Hobby:
Favourite Web Site:  

'bdy>

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

< ?,

n .

.

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~extl ) ;

.%, ,

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
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="> < % = v i e w g . e t p r ~ d u c t( 1 % > < / t d > 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

....

.... . ..... .... ..,.,

I

rr/@~ocal

intranst

ist to

A

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 ' . - 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":

-

c t ~ o d y h g c ~ ~ l o r i= l FFFFFF1'> " < p > L c ~ q i r < f e r n 1 m e t t , o d = " p u c t 1 ' a c t i ~ r ~ = " c e cl hl , 3 s e n u > W r o x S a m p l e C o d e - Routing Step

< 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 > < a href="manufactureroute">C1ick h e r e w h e n completed.

  < / p >

 



Finalrnente, despuis de que se hayan rnostrado todos 10s pasos de redireccionarniento, se introduce la inforrnaci6n de envio:

Capitulo 18

1

Archlvo

]

C AtrBs

li-

II

EdkltKl

Ver

Favoritos

- +-@a ,

(

HerrMnientas

@Bisque&

Ayuda

-

Favoritos C@~ultimedia

-

aI 1 @1

r

S h p the manufactured product:

La vista es proporcionada por s h i p . j s p :

Wrox Sample Code

-

Ship the Product

Ship the manufactured product:





 



Proporcionamos un archivo HTML que puede ser utilizado como archivo de bienvenida para esta ap~icaci6r1,~larnadoindex. html:

Wrox Sample Code - Manufacturing Application

Roles de desarrollo y de implementaci6n ,'./hea.j?

F a c t o r y Demo f o r J S F s a n d E J B s < / h l >

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

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

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:

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



< W e b - u r i \ j s p s :xar

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 , 6 0 L 1 0 0 0 L ); ..

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 ; Q u e u e C o r ~ r i e c t i o n F a c t o r y q u e u t C o n r ~ e c t i o n F a c t o r ~=. n u l l ; 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 = n e w 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 n d i C o r ~ t e x .t l o o k u p ( " Q u e u e C o n n e c t i a r ~ F a c t o r y " ); q u e u e = ( Q u e u e ) j n d i C a r i t e x t . l o o k u p ( " W r o x O r d e r s W) ; } 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 ~ D o e s t h e q u e u e 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 t ri ~ ( ) ; 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 ? r c~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); q u e u e C < : > n n e c t i o n .s t a r t ( ) ;

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 catch

(JMSException jmsEx)

{

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) [ ]

1

I

"

t

..-

( ) );

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 ( ) ) ;

1

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 e i vy eW r o x L i s t e n e r : 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 19

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 a n t e r i o r ~ r o x ~ u e u e ~ e nydseurs 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 " 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 h e rsimilaral , 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

- a 8 : i . i i r ~ i , = n e e t i n a t i o nL . l r c : i E ' ~ ~ hI lc a t i i.ri.=

r;:,(.,ii

Compile a h o r a ~ r o x ~ o ~ i c ~ u b l iejecutando 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 l i sa vt V ~ 3e ~ - .

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 = t o p i c C o r ~ n e c t i o n . c r e a t e T o p i c S e s s i o r(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

I

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

jmsEx. tostring (

t

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 nn so 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 \ 1i zq r\ ~jnmf--~c l i e r l t . ~ r i l p r r it e s -.zrr

Debe ver algo asi:

.;4J:EF:

-

HOP:F*?lik,\jLre.jRT;

!'!r~?:.:T~~pi~S'~hss:rit.er

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

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 iybde er s p u ~ s ~ r o x ~ o p i c ~ u b l i obtenemos resultados:

I I

El orden d e 10s mensajes serP aleatorio porque 10s mensajes se reciben asincr6nicamente. P o d e n ~ o sver 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

Descripci6n

BytesMessage

Utilizadapara enviarun mensajequecontengaun streamde bytes sin interpretar.

Connection

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.

f

Connection Factory

Encapsula un conjunto de parimetros de configuracidn que han sido definidos por un administrador.

Connection MetaData

Proporciona informaci6n que describe la connect ion.

DeliveryMode

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.

Destination

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.

Except ion Listener

Si un proveedor JMS detecta un roblema grave con unaconnect ion,informari a1 ExcevtionListener de a conexi6n. si se ha registrado una.

P

tabla continua

-

siguiente

Capitulo 19 Interfaz

Descripcih

MapMessage

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.

Message

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.

d

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

Encapsula un nombre de cola especifico del proveedor.

QueueBrowser

U n cliente utiliza un QueueBrowser paraexaminar mensajes en una cola sin eliminarlos.

Queueconnection

Una conexi6n activa a un proveedor JMS punto-a-punto.

JMS y beans controlados por mensaje Interfaz

Descripcibn

QueueConnection Factory

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

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.

Queuesender

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

Utilizado para enviar un flujo de primitivas Java.

TemporaryQueue

U n objeto exclusivo~ueue creado para la duracidn de u n a ~ u e u e c o n n e cito n .

TemporaryTopic

U n objeto e x c ~ u s i v o ~ ocreadopara ~ic l a d u r a c i d n d e u n a ~ o p i c ~ o n n eicotn .

TextMessage

Utilizada para enviar un mensaje que contengan un s t r i n g .

Topic

Encapsula un nombre de apartado especifico del proveedor.

TopicConnection

Una conexi6n activa a un ~ r o v e e d oJMS r pub/sub.

TopicConnection Factory;

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.

TopicPublisher

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

I

Interfaz

Descripci6n

TopicSession

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?

0

i C o m o se reajusta la clusterizacibn?

CI iQuk sistema operativo recomienda en proveedor? 0

iRealmente necesita todas las funciones bonitas per0 n o estindar?

O

Si estamos buscando velocidad, inecesitamos mensajeria punto-a-punto o pub/sub?

EI

iQuk sucede con el rendimiento cuando empieza a afiadir selectores de mensaje? iQuk ocurre cuando afiade un suscriptor duradero?

o Si la pkrdida de un mensaje o la entrega de un duplicado puede costarle dinero, ise centra en proveedor en la fiabilidad en lugar de la velocidad?

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 " ); m s g . 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 ~. cso 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 Oes~una . C Olas ~ )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 M e s s a g e D r i ~ e n B e a n e s ~ e c i f i cs61o a dos mitodos: 0

void e j bRemove ( ) es invocado por el contenedor justo antes de que el bean sea eliminado

0

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

0

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:

f! Reserva preparada r para rnetodos

onMessaqe ( ) ', I

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

a

Gestionadas p o r contenedor

st as

afectan a 10s atributos transaccionales del metodo onMessage ( ) y a1 manejo de la entrega de mensajes garantizada.

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

1

0 Description...

1I

.

Manifest Classpat

Icons.,

1

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~sebean that you are creating ar~dselect 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.

I ' r n i o i ~lnrwf wrc

Y"hrFlC1@~;11?

0Description...

1

--

mi, ...

1

1.-

Selcccione el tipo de bean Message-Driven, In clase de bean e introduzca el n o ~ n b r cde 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

I

I

JMS hlessaqe Selwlor:

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!

0

(0WrOXApP

v

Tarpet SBI%VT:

localhod

t

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:

WroxMDBear~

This is

the

Wrox

descriptior~

WroxMDBear~ < e j b - n a m e > W r o x M D B e a r ~ < / eb-name> j < e j 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 ~ < / ebj- c l a s s > Bear~ Client NOT N U L L < / m e s s a g e - s e l e c t o r >

Auto-ackr1o~1edge

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









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

0

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

0

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

Temas de integracion EIS y el rol de JCA

0

Arquitectura, servicios y API JCA

0

Como funciona JCA en un sistema J2EE

0

Programaci6n con la Interfaz Comfin de Cliente (CCI)

0

Construccion de un componente JCA

0

Reglas que debe seguir un desarrollador JCA

0

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

Aplicaciones de Planificaci6n de Recursos de Empresa (ERP), como SAP R/3 y BAAN.

0

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.

O Las aplicaciones Web de gran escala requieren aha disponibilidad y reajustabilidad respecto del

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

1

[~ontenedorWeb

I

' .

--

-' i

EIS

f

-

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.

0

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.

0 Interfaces de ernpaquetado y despliegue- Permiten a 10s diversos adaptadores de recursos EIS

conectarse a aplicaciones J2EE. 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

1

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

JDBC 2.0

JCA 1.0

Definicion

Proporciona una interfaz genkrica para interactuar con bases de datos relacionales

Proporciona una arquitectura estindar para que J2EE y aplicaciones Java integren e interactiien con recursos EIS

API

Define un API Java estandar para acceder a bases de datos relacionales

Utiliza la Interfaz Comiin de Cliente (CCI) paraproporcionar un API independiente de EIS

Conexion

Usa controladores JDBC especificos para RDBMS

Utiliza un adaptador de recursos EIS para interactuar con un EIS

I

La tabla continua en la pcigina siguiente

Capitulo 20 JDBC 2.0

JCA 1.0

Los servidores J2EE im lementan mecanismos de reserva l e conexiones DBC para crear conexiones a una ase de datos

Los servidores J2EE implernentan contratos de servicio JCA para establecer una factoria de conexiones y gestionar conexiones con un EIS

Apoya aplicaciones no gestionadas (aplicaciones de dos niveles), que uthzan JDBC

Apoya aplicaciones no gestlonadas (aplicaciones de dos niveles), que utilizan C C I

Apoyo a la Interfaz de Proveedor de Servicios (SPI)

Proporciona apoyo (desde JDBC 3.0) y relacion con SPI JCA

JCA define SPI para servicios integradores de servidor de aplicaci6n, como transacciones, conexiones y seguridad

Apoyo de transacc16n

Apo a transacciones XA y no-XA con ruentes de datos XA rubyacentes

Apoya transaccionesXA y no-XA con recursos EIS subyacentes

Apoyo JTA

Pro orciona una interfaz para el apoyo y JTS a

Apoyo a JTA con un contrato entre el estor de transacciones J 1 ~gestor ~ de recursos EIS

Implementaci6n de Servidor

i

PA

5

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.

o

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

Identification de usuario, autentificacibn y autorizaci6n.

0

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.

0

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.

0

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.

0 Autentificar el principal de 10s recursos si la conexi6n a h no esti autentificada. 0

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.

0

Controlar el acceso a recursos EIS.

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.

I

1

-Adaptador de Recurso Adaptador de Recutso Recursos b -, Ernpaquetado Procedente de Modulo de Procedente del

lncluir M6dulos J2EE

Servidor de Aplicacion J2EE

Contenedor

Adaptador de

- - -- - -

Conf~gurac~on del Entorno Procedente del Desplegador _ __

/

I-

1

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:

0

La c l a s e ~ a n a ~ e d ~ o n n e c t i o n ~ a el c tproveedor or~; del adaptador de recursos especifica el nombre cualificado completo de la clase Java que implementa la interfaz javax.resource.spi.ManagedConnectionFactory.~ore~emplo:

a

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 oelr yproveedor ; del adaptador de recursos especifica el nombre cualificado complete de la interfaz y clase de implementaci6n Java para la factoria de conexiones. Por ejemplo:

]avax.sql.DataSource

corn. sun. connector. blackbox. JdbcDataSource

a

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 teloproveedor 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 cot 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:

BasicPassword

javax.resource.security.PasswordCreder~tia1

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

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

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

javax.sql.DataSource

com.sun.cor~r~ector.blackbox.JdbcDataSource

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 >

com. sun. connector. blackbox. JdbcConnection

N~Tra~i~a~tior~ con fig-property>

Capitulo 20 Connect ionURL j ava. lar~q. Strlnq

jdbc:cloudscape:rmi:CloudscapeDB;create=true



BasicPasswqrd

javax.resource.security.PasswordCredentia1

fa1se

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

0

La c l a s e ~ a n a g e d ~ o n n eicot 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 .

0

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.

ad especifica el nivel de apoyo de transacci6n proporcionado por la o C ~ m ~ a t i b i l i d transaccional: 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). 0

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

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

1

blackbox-notx. r a r

Para apoyarNO-TRANSACT I O N

(

blackbox-xa. r a r

I b l a c k b o x - t x .r a r

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

Para adaptadores de caja negra no-XA (que utilizan niveles de transaccibn no-XA):

O

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

(

);

accountid

VARCHAR(3) CONSTRAINT Demoaccount pk PRIMARY KEY, firstname VARCHAR(25), lastname VARCHAR(251, balance DECIMAL(12,2)

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

I

Application File N a n : c:\WroxZProJavaSe1venCh20\81ackbo~BIackbo~.ear

( 1 ~rowse,. I

I ApplicationDisplayName: I

QK

II

cancel

II

... I

Help

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 [email protected]~Ch?bRlachboylB!~chbOx ear

Appllcmort DISIIIW Name: -

I

Coraenls: MNIFEST MF

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

Help

*IS

iampGqm p1ppqEqF --F l J fl'Ej@1-p J --

-

9 UFIIP; Q

flApplications 9 0 Blackbox

~ ~ S ~ J P C I I ~ ~ A Fj ) Ip~l ~Pl rSl ~ o ~Filackbox ?b AlackRo~Lo nlTx ~

1 1 6 &¶l~ flw--~

+ I GF*~ )

fi BIackBowLocalTx

9 @ Sewers

f l localhost Managed Cnclnscllon raclory.

I

...

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

I I

Recovery Settings -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;

public DemoAccount

findByPrimaryKey(String accountid)

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

I

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. " ) ;

i

1

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 :

"

+

ex.getMessage());

1

public void ejbActivate ( ) [ accountid = (String)context .getPrimaryKey( ) ;

1 public void ejbpassivate ( ) accountid = null;

I

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

I

storeRow( ) ; ) catch (Exception ex) i throw new EJBException ("ejbStore: 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

=

I

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();

I

else I prepstmt. close ( ) ; throw new NoSuchEntityException("Account " " not found");

t

+

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

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

I

Referenced Bv DemoAccount

I

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

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 ;

public

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 = ( D e m o A c c n u n t H o m e )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));

I

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;

"

);

1

I 1 Finalmente, ejecute ~ e m o ~ c c o uCnl 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~inmentecomo "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 configuraci6n de i n s t a n c i a s ~ a n a g e d ~ o n n ei cotn F a c t o r y . 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:

0

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:

0

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:

public

interface javax.resource.cci.ConnectionFactory extends java.io.Serializable, javax.resource.Referenceable

public RecordFactory getRecordFactory0

{

throws ResourceException;

public Connection getconnection0 throws ResourceException; public connection getConnection(javax.resource.cci.ConnectionSpec properties) throws ResourceException; public ResourceAdapterMetaData getMetaData0 throws ResourceException;

1

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;

public void rollback0

throws ResourceException;

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)

createlnteraction

rn

-I

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 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 n .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 odefiniendo 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

0 Recurso EIS

Gestionad

Recursos EIS

1

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 conFactory 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 rinvocael 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 eicon. 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 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 ~ a p p e d R 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,i e m ~ l oes una a~licacionde 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. cf = (ConnectionFactory) ic. lookup ("java: comp/env/eis/wroxCCIEIS" ) ; 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 econ 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;

j

{

un nuevo objeto CciConnectionSpec con 10s usuario y de contraserla

ConnectionSpec spec

// // // //

( )

=

new CciConnectior~Spec(user, password) ;

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 ) ; IndexedRecord iRec = rf. createIr~dexedRecord("Ir~putRecord" / / Configurar 10s valores boolean flag = iRec.add(name) ; flag = iRec.add (new Integer iqty) ) ; / / Ejecuta la interacci6n ix.execute(iSpec, iRec); 1

I

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 0utiliza ~ ~ .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

)

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

=

"

t

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~( " j d b c :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 ?, ? ) " ) ;

.

j

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 :

-

1

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

C o n w c l l u r ~Factory JNOI Nnrrln:

rrj.;.hriiaxi:cIEgi, Cor~fiijlrralinnPropeflies-

PropertV ConneclronURL

I

Twe

String

-1

value jdbc cloudscape rml Clou

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

@ CClAdapler 9 tclblatkbox-bcrar eisl~row~~l~w

1

EM."

I

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:

9

C j Applical~ons 0-

0 Blackbox

9 0 CClAdapter 0- @ BookStore G% CciBlackBoxLocalTn

8

P Sewers

Ref Type !esource -

I

Referenced By ( Reference Name BookStore ewWroxCCIEIS -1

1

JNDl Name

I

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

J C A permite a las orgnnizaciones aumentar las ventajas d e sus sistemas EIS existentes y d e JZEE.

-1

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

0

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.

0 N o existe un mecanismo integrado de compatibilidad XML disponible para recuperar datos XML,

aunque C C I puede utilizarse para compatibilizar 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

Los adaptadores de recursos

0

Implementaci6n y prueba de un adaptador de recursos

0

Programaci6n con la Interfaz Comun de Cliente (CCI)

0

ImplementaciCln y prueba de una aplicaci6n debase J C A

0

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

0

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 ny 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. Arnbas cornbinan rndtiples niveles, clientes infradotados o dotados, ~rotocolosde obietos distribuidos. 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:

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.

EI U n

CI

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.

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

Client/Sewer Programming with Java and C O R B A , Orfali y Harkey. ISBN 0-471-24578-X

O

Enterprise JavaBeans, Second Edition, Mozon-Haefel. ISBN 1-565-92869-5

O

The Java 2 Enterprise Edition Developer's Guide (referenciado en la documentacion J2EE y disponible enhttp://java.sun.com/j2ee/docs.html)

O

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

Los componentes que realizan las tareas de empresa de la aplicaci6n

0

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

1

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.

O

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.

0

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

I

I

4

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,

%

1

1..* -

FachadadeSesh

1 ..* .

Objeta de Empresa

L

< < U B de EnI~dadz >

< >

ObJetode Empesa2

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

de empresa

1 1

I

I I I

I

I I

I I

Cresr un Buscar

-I I I

I

-.-

< > Objetode

Ernpresa

-

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

ri"; 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

4

El 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 ~ m b i o spotenciales 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

'F'-l+. L. y crear

.Buscar

Cliinte

-

.

1 ..*

1

4

Delegado de Ernpresa

I..*-

,

r,

--.A

*

Objelode Empresa

P P

cz

Objeto de Ernpesa2

ObJetodaEmprew3

i

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~npreque 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 ~ ;

1

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

I

utiliza

1

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 ny g e t p r o p e r t y . 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 r 1

Cliente

1

Controlador Frontal

1

%

Lanzador

1I..*.

Vista -

Ayudante

,,* .

7

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

< r Vista

I

1

1

I

1

1

I..*I..*

I

Ayudante Avud

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

Nivel Web

--

--

I I

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:

-El Objeto Valor

Lista de Valores

I ) proporciona datos

I

--" Consideraciones de diset7o para aplicaciones J2EE

El diagrama de secuencia tiene este aspecto:

Obtener datos

-&llect~on>

Obtener pr6x1mo

I

I

I I I

I I I I

I

I

I

I

subconjunto

4-

- - -- ---

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

I

\r""

ut~lizapara actualizar

Objeto de Empresa

E l

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.

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

El c6digo cornGn puede ser cornpartido por mGhiples piginas, proporcionando servicios comunes y reduciendo en esfuerzo de mantenimiento

U

La reduccicin o eliminaci6n del c6digo facilitari la vida a1 diseiiador de piginas Web sin c6digo

3 La mayoria de 10s cambios en el funcionarniento del c6digo no requeriri las piginas que utilicen ese

c6digo para ser editados 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.

LIsccuenciaci6n 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 [email protected]. 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 ~rccidnliigica presentada a l f l u ~ ode 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

Base de datos .--

:

-k

.

Y

--

:4-"*-'

JSP

I

-

b

I

RMI

C -

RMI

-

reserva de conexiones

-

Base de datos

J DBC

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:

I

Tipo de Aplicaci6n

Tecnologias

Complejidad

Funcionalidad

Solidez

Piginas HTML

Piginas HTML

Muy poca

Muy poca

Mucha

Piginas HTML, piginas JSP, servlets

Poca

Pocn

Poca

I

Consideraciones de diseAo para aplicaciones J2EE

I

T i p o d e Aplicaci6n

Tecnologias

Complejidad

Pdginas JSP con componentes modulares

Piginas H T M L , Media plginas JSP, servlets componentes JavaBeans, etlquetas personalizados

Piginas JSP con cornponentes modulares y Enterprise JavaBeans

Piginas HTML, Mucha piginas JSP, servlets componentes JavaBeans, etiquetas personalizados, Enterprise Java eans

Funcionalidad

Solidez

Media

Media

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~entaIn 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 ocompleto 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~osdirectamente 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 factores determinantes aqui son si un ~ r o d u c t otiene funcionalidad asociada, adem.is de datos, y si necesita transacciones. Si un ~ r o d u c t oes 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 ~ r o d u c t ono 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

Identificar al usuario

O

Mostrar el catllogo de productos a1 usuario

a

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:

I

: :

Base d e datos E"cepcibn ecupada, intbntelc I--, TooManyLocks I I I

,

I

I

.-

I I

lnterfaz d e nivel inferior

----..-

!

I I

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~licacionesJ2EE 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~ecificodel 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 O r d e r i n g W o r k f l o w y ~ r o d u c t ~ i s t e r . T ya 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 .~lrnacenarseel 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.

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.

-1 Estado e n

Si el sistenla dcbe npoyar clientes infradotadob, entonces deben proporcionnrbe alguno\ metodo5 d o s t i n ~ d o sa 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~ancjadnpor 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 ~ m p l e m e n t a d ac 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~plementadacorno 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~nad 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~nacenadoen 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

4

A

Tan larga como desee

4

Ntjmero de recursos

Fraccibn de tiempo

v

v Uno

b

4

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

A

7-

ja~a.ejb.~~~~bj%T_/ -

--

A--

-

Consideraciones de disefio Dara a~licacionesJ2EE 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 uantipoAccountAdmin 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:

a

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)

O

Utilizar el patron de Ayudante de Vista en piginas JSP divide la codificaci6n Java de la presentacion de datos

0

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

0

Los elementos de funcionalidad de interfaz de usuario pueden ser tratados de forma independiente construyendo una Vista de Composici6n

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.

0

El uso de una Fachada de Sesidn reduce el numero de llamadas procedentes del cliente para el nivel de empresa.

0

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.

0 Aplicacidn del patr6n de Objeto de Acceso a Datos para proporcionar una interfaz de cliente

c o m h a multiples fuentes de datos. 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

Los servicios especificos de rnensajeria integados en software intermediario orientado a1 rnensaje con rndtiples arquitecturas corno punto-a-punto y publicar-y-suscribir

0

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.

0 Corno el contexto provisto por un tip0 determinado de aplicaci6n puede afectar a la aplicaci6n de

base J2EE.

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.

n

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:

I

U n componente de aplicaci6n accesible a travks de protocolos Web estindar.

I

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:

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 ~ ebursitil 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 ~esr i3 c4 e. 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, TPGE son tratados corno estindares de facto para " 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:

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

0

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: ? ? *

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

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

=

D r i T ~ t r M a n a g e rg.e t C o r ~ r ~ e c t i o(rui 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 FROM s t o c k d e t a l l s 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 ); +

/ / Mostrar e l conjuntc de resultados while ( r s . n e x t ( ) ) [ price = rs.getString(2); result= true; break;

WHERE

(stocksymbol="'

t

Capitulo 22

1

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

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

stockdetails

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

I

r r

EJB Jar File COM Dispatch Interface

I

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

Classpath

F Yfi/ro~IProJa\raSeruenCh227slockjar Output Filename

P I

Properly Name

r I

n Value

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

-

Back

I1 7 1

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 ,TDUSDL 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:

coperat ion narne="getStockPrice">





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,< 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 equivalente que describa el m6dulo. Los EJB son descritos utilizando la etiqueta < e j b>, las a~licacionesWeb son descritas utilizando la etiaueta . 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 utilizando la etiqueta< j ava>. A excepci6n de la e t i q u e t a < ~ e b >el, contenido de las otras etiquetas 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 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 , < c o n n e c t o r > y < j ava>.Laetiqueta

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 exclusive. Dos aplicaciones Web empaquetadas en el mismo archivo EAR no pueden tener valores idhticos. Si s610 hay una aplicaci6n Web en el archivo EAR, el valor de 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 jnava . es el siguiente: package

wrox;

import

javax.ejb.*;

public

class EnterpriseBean

implements

SessionBean

I

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 ("Title") ; out .println ("") ; out .println ("See console to ensure EJB was invoked. ") ; out .println ("");

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

< a l t - a d d > es una sub-etiqueta de . 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 es el siguiente:

Empaquetado e implementation J2EE

This is administrator's security role

Administrator

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~ltiplesm6dulos 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 ~ I N- 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~esde 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 b i b 1 i o t e c a w ~ ~I-N F \ l i b si una aplicacion Web depende de ella. Adicionalrnente, la necesidad de 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

CI Q u e 10s cargadores de clases sean rnodificadas para buscar paquetes opcionales y rutas de aplicacion

para clases 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~EB-I 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