Introducción a EJB 3.0

0 comentarios
Enterprise JavaBeans (EJB) es una plataforma para construir aplicaciones empresariales portables, reusables y escalables, utilizando el lenguaje de programación java. EJB permite a los desarrolladores de aplicaciones enfocarse en construir la lógica de negocio sin la necesidad de gastar tiempo en la construcción de código de infraestructura.
Desde el punto de vista del desarrollador, EJB es una pieza de código java que se ejecuta en un ambiente de ejecución (runtime enviroment) denominado contenedor EJB.

Estándar Java EE
EJB es una parte muy importante del estándar Java EE. EJB 3 es una especificación de una API abierta y publica, la cual es utilizada por diversas organizaciones para crear una implementación de un contenedor (container) o un proveedor de persistencia (JPA). El estándar EJB 3 es desarrollado por la Java Community Process (JCP), la cual está constituida por un grupo no exclusivo de individuos que guían los estándares Java.
Por este motivo, EJB es soportado por un gran número de organizaciones independientes. Esto incluye tanto a las grandes corporaciones como Oracle e IBM, como también a los grandes grupos open source como JBoss y Geronimo.
El alto grado y variedad de soporte de esta especificación se traduce en tres importantes ventajas para el desarrollador y compañías que trabajan con esta tecnología:
  1. No se encuentran a merced de los altos y bajos de una compañía o grupo de usuarios en particular.
  2. Un gran número de personas tienen el interés (a corto, mediano y largo plazo) de mantener esta tecnología lo más competitiva posible.
  3. Todos los proveedores de la especificación históricamente han competido agregando nuevas características (no estándar) a sus implementaciones.
Todos estos factores mantienen la especificación EJB en el camino de la evolución constante.
El proveedor de persistencia está completamente separado del contenedor EJB 3.0, por este motivo, es abstraído a través de la Java Persistence API (JPA). Esto permite, en un proyecto, intercambiar la implementación del mismo sin cambiar ninguna línea de código. Existen organizaciones que brindan implementaciones de la JPA, para que el mismo pueda ser utilizado dentro de un contenedor completo Java EE, con contenedores web livianos (como Tomcat), o para utilizarlas dentro de aplicaciones Java SE. JDO, OpenJPA, Hibernate (de JBoss) y TopLink (de Oracle) son algunas de las implementaciones más utilizadas. 

EJB como un componente
En el mundo de EJB 3, un componente no es más que un POJO (Plain Old Java Object) con cierta funcionalidad especial. La idea real detrás de los componentes es que permiten encapsular el comportamiento de la aplicación.
Existen tres tipos de componentes EJB:
  • Beans de sesión (session beans)
  • Beans manejados por mensajes (message-driven beans)
  • Entidades (entities)
Los session beans y message-driven bean (MDB) son utilizados para implementar la lógica de negocio en una aplicación EJB, y los entities son utilizados para la persistencia. Estos componentes pueden ser reutilizados en diferentes aplicaciones, lo que obliga a construirlos de una manera cuidadosa y planificada para permitir reutilizarlos.

EJB como un framework
Como ya se menciono, los componentes EJB están alojados en un contenedor. Ambos, los componentes (o EJB’s) junto con el contenedor, pueden ser vistos como un framework que provee servicios para el desarrollo de aplicaciones empresariales.
El contenedor EJB provee servicios comunes a la mayoría de las aplicaciones del lado del servidor, como el manejo de estados de una aplicación, almacenamiento y obtención de la información desde una base de datos, manejo de transacciones, implementación de seguridad, procesamiento asincrónico, integración de sistemas, etc. Estos servicios están disponibles para los componentes EJB cuando los mismos son desplegados (deployed) en un contenedor EJB. De esta manera se permiten desarrollar aplicaciones profesionales en menor tiempo y enfocarse solo en la lógica de negocio.
El contenedor provee los servicios a los componentes EJB a través de las anotaciones metadata (metadata annotations), estas son utilizadas para preconfigurar los componentes EJB especificando los tipos de servicios, los cuales son agregados cuando el contenedor despliega los mismos.
Las metadata annotations (introducidas en Java 5), son seteos de propiedades que se aplican a una pieza de código, como un método o una clase. Este es un tipo de programación declarativa, en donde el desarrollador especifica que debe ser realizado y el sistema agrega el código necesario para realizarlo. Estas anotaciones permiten no depender de un archivo XML de configuración externo. De esta manera, los desarrolladores agregan los servicios declarativamente a los componentes EJB, es decir, las anotaciones transforman un simple POJO en un EJB.
El framework EJB es un estándar de la tecnología java, el cual tiene una especificación abierta (administrada por la Java Community Process). EJB es soportado por un gran número de compañías y grupos de open source que proveen implementaciones de la especificación. Dichas implementaciones deben cumplir con la especificación, lo cual facilita la portabilidad de las aplicaciones a través de diferentes contenedores EJB.

Arquitecturas de capas y EJB
La mayoría de las aplicaciones empresariales contienen un gran número de componentes. Para desarrollar este tipo de aplicaciones se puede seguir una arquitectura común o un principio de diseño (patrones). En una arquitectura con capas, los componentes son agrupados dentro de diferentes capas, cada una de estas delega trabajo a su capa por debajo.
EJB permite construir aplicaciones utilizando dos arquitecturas de capas diferentes: la arquitectura tradicional de cuatro capas y el diseño manejado por el dominio (domain-driven design).

Arquitectura de cuatro capas
En esta arquitectura, la capa de presentación es responsable de renderizar la interfaz grafica del usuario (GUI) y manejar la entrada del usuario. La capa de lógica de negocio es el corazón de la aplicación y contiene flujo de trabajo (workflow) y lógica de procesamiento. La capa de persistencia provee una abstracción orientada a objetos (OO) de alto nivel de la capa de base de datos. La capa de base de datos consiste típicamente en un sistema de administración de bases de datos relacionales (RDBMS).
EJB da soporte para la capa de lógica de negocio y la capa de persistencia. Los session beans y MDB residen y utilizan los servicios de la capa de lógica de negocio. Por otro lado, los entities residen y utilizan los servicios de la capa de persistencia.

Domain-driven design
El termino domain-driven design (DDD) enfatiza que los objetos de dominio deben contener lógica de negocios y no deberían ser solo una réplica (sin lógica) de las tablas de la base de datos. En EJB, los objetos de dominio son denominados entities (entidades).
En versiones anteriores de EJB (como EJB 2), era casi imposible implementar un modelo de dominio real debido a que los beans no eran POJO’s y no soportaban muchas características OO, como la herencia y el polimorfismo. EJB 3 permite implementar la arquitectura DDD, debido a que las entidades son definidas a través de JPA (EJB 3 Java Persistence API), la cual soporta todas las características OO dado a que son POJO’s con simples anotaciones.

Session Beans
Un session bean es invocado por un cliente con el propósito de realizar una operación específica de negocio. Es decir, puede ser utilizado para crear cualquier funcionalidad lógica de la aplicación. Existen dos tipos de session beans: stateful y stateless.
Un stateful session bean almacena automáticamente el estado del bean entre diversas invocaciones de un cliente sin la necesidad de que el desarrollador deba escribir código adicional.
Un stateless session bean no mantiene ningún estado y permite modelar servicios de aplicación que pueden ser completados en una sola invocación del cliente.
Un session bean puede ser invocado tanto local como remotamente utilizando Java RMI (Remote Method Invocation). Un stateless session bean puede ser publicado como un web service.

Message-driven beans (MDB)
Del mismo modo que los session beans, los MDB’s procesan lógica de negocio. Pero con la diferencia que los métodos de los mismos nunca son invocados directamente por un cliente. Los MDB’s son desencadenados por mensajes enviados a un servidor de mensajes, el cual activa el envío de mensajes asincrónicos entre componentes del sistema. MDB’s son utilizados típicamente para sistemas robustos de integración o procesamientos asincrónicos. IBM WebSphere MQ, SonicMQ, Oracle Advanced Queueing y TIBCO son algunos de los servidores de mensajes más utilizados.

Java Persistence API (JPA)
La persistencia dentro de EJB 3 es administrada por JPA. JPA permite persistir automáticamente los objetos Java utilizando una técnica denominada object-relational mapping (ORM). ORM es esencialmente el proceso de mapear la información contenida en los objetos Java hacia las tablas de base de datos utilizando una configuración.
JPA define un estándar para:
  • La creación de configuración metadata del ORM para mapear entidades hacia tablas relacionales.
  • La EntityManager API, una API estándar para realizar las operaciones CRUD (create, read, update y delete) de las entidades.
  • El lenguaje Java Persistence Query Language (JPQL), para realizar búsquedas y obtener información persistida de la aplicación.
Como se ha mencionado anteriormente, desde que JPA estandariza los frameworks ORM para la plataforma Java, se pueden utilizar productos como Hibernate ó TopLink como la implementación del proveedor de persistencia de una aplicación. Como JPA está completamente separado del resto del contenedor EJB 3, y en definitiva todas las operaciones se traducen a operaciones JDBC, esta tecnología de abstracción de ORM puede ser utilizada en ambientes Java SE.

Entities
Las entidades son objetos Java que son persistidos dentro una base de datos. Es decir, son las representaciones OO de la información de la aplicación almacenada en la base de datos. La magia de las entidades se basa en las anotaciones metadata ORM, las cuales especifican la información de cómo las mismas deben ser mapeadas a la base de datos. Las entidades JPA soportan todos los tipos de relaciones y capacidades OO, incluyendo relaciones entre entidades, herencia y polimorfismo.

EntityManager
La interface EntityManager administra entidades en términos de proveer servicios de persistencia. Dicha interface, lee las anotaciones metadata de una entidad y realiza las operaciones de persistencia. Es decir, conoce el modo de agregar, actualizar, eliminar y obtener entidades de la base de datos (CRUD).

Contenedores completos Java EE
Un contenedor Java EE es un servidor de aplicaciones el cuál contiene un contenedor EJB 3, un contenedor web y otras API’s y servicios Java EE. Algunos ejemplos de contenedores Java EE completos son: WebLogic Server (BEA), GlassFish (Sun Microsystems), IBM WebSphere, JBoss Application Server y Oracle Application Server.
Algunos proveedores pueden ofrecer solo un contenedor web (como Tomcat) o proveedor de persistencia (como Hibernate).

Otros beneficios de EJB 3
Además de los beneficios expuestos anteriormente, EJB 3 ofrece:
  • Utilización de servicios EJB: Integration, Pooling, Thread-safety, State managment, Messaging, Transactions, Security, Interceptors, Remote Access, Web services, Persistence, Caching y performance.
  • Modelo de programación simplificado, a través de la utilización de POJO’s (Plain Old Java Objects) y POJI’s (Plain Old Java Interfaces), a los cuales luego se le aplican configuraciones a través de las anotaciones para agregar servicios de la plataforma.
  • Anotaciones en cambio de descriptores de despliegue (archivos XML).
  • Inyección de dependencia en vez de JNDI lookups. Esto permite desacoplar el código de la aplicación del servidor, los lookups se convierten en una simple configuración a través de anotaciones.
  • Estandarización de frameworks de persistencia (JPA).
  • Componentes POJO más fáciles de testear a través de frameworks de testeo como JUnit o TestNG.
  • Integración de EJB 3 con Spring, Spring con EJB 3 y Spring con JPA.

Sun Certified Business Component Developer (SCBCD)

4 comentarios
Luego de rendir mi certificación SCWCD (el 23 de diciembre de 2009) me decidí a tomarme un tiempo de descanso durante enero de 2010. Una vez pasado dicho mes, comence lentamente a leer e investigar los temas tratados en la certificación SCBCD (CX-310-091), solo con el objetivo de ver por donde continuaría mi camino por aprender Java EE. Más que nada por la disyuntiva "seguir el camino de las certificaciones o comenzar con alguno de los tantos frameworks existentes para trabajar con esta tecnología". En un principio supuse que lo más conveniente sería comenzar con algún framework de los más mencionados (Hibernate, Struts, Spring, etc), pero al leer los dos primeros capítulos del libro "EJB in Action" de Manning, me dí cuenta de que estaba equivocado.
Por ese motivo fue que me decidí a comenzar a investigar lentamente sobre EJB 3.0, y en una vez que maneje los temas tratados voy a rendir la certificación SCBCD. A diferencia de las certificaciones anteriores que rendí (SCJP y SCWCD) esta me la voy a tomar más tranquilo y la prepararé más despacio (más que nada porque dentro de poco comenzaré a trabajar para una empresa de software si todo sale bien).
Como ya se ha mencionado en este blog, el programa de certificación de SUN (ahora de Oracle) actualmente contiene ocho exámenes de certificación sobre la plataforma Java:

"Esta certifición está dirigida a desarrolladores de componentes EJB (Enterprise JavaBeans) encargados de diseñar, desarrollar, probar, implantar e integrar aplicaciones EJB. Para obtener la certificación, es preciso aprobar un examen. Los candidatos ya deben poseer el título de Programador Certificado en Sun (SCJP), en cualquiera de las ediciones."

Tutorial Java EE 5
Por otro lado les recomiendo el tutorial oficial de sun de Java EE 5. En dicho tutorial se cubren todos los temás de la tecnología J2EE 5. Por lo tanto pueden encontrar información de utilidad para las certificaciones SCWCD, SCBCD y SCDJWS.
Más allá de esto, considero que este tutorial sirve también para brindarnos los materiales de estudio para esta tecnología, y a su vez, una manera ordenada de abordar los temas si no lo quieren realizar a través de las certificaciones.
A través de este tutorial queda claramente reflejado el hecho de que es altamente recomendable conocer todos los temas en profundidad, antes de comenzar con un framework de desarrollo. Como ya mencione, es una fantástica guía para seguir en nuestro camino de aprendizaje de la plataforma.

Detalles del examen
  • Se rinde en: Centros autorizados por Prometric
  • Prerequisitos: Sun Certified Java Programmer (cualquier edición)
  • Tipo de examen: Multiple Choice, preguntas basadas en un escenario y Drag and Drop
  • Número de preguntas: 61
  • Puntaje de aprobación: 59% (36 of 61 preguntas)
  • Tiempo disponible: 145 minutos
Bibliografía
Actualmente estoy leyendo el libro "EJB in Action" de Manning, a continuación les dejo el link así pueden descargarlo:
Bueno para finalizar les digo que estén atentos a este post (si les interesan los temas relacionados a la certificación SCBCD), ya que a medida de que voy investigando agregaré aca mismo cualquier otra información de utilidad o bibliografía que encuentre.

eBooks SCJP

2 comentarios






SCJP Sun Certified Programmer for Java 6.pdf

CD ISO





















Thinking In Java 4th Edition.pdf

Indice SCBCD

0 comentarios
Info General
Recursos

Indice SCWCD

2 comentarios
Info General
Recursos

Indice SCJP

29 comentarios
Info General
 Recursos
Revista JavaWorld

eBooks SCWCD

8 comentarios
Libros para realizar la preparación de la certificación SCWCD:







Manning SCWCD Exam Study Kit - 2nd Edition - May 2005







OReilly Head First Servlets & JSP - 2nd Edition - Mar 2008









NOTA: El libro de MANNING esta creado para la versión CX-310-081. Sin embargo, recomiendo la lectura de este libro ya que fue de mucha utilidad para mí preparación. Ciertos temas se desarrollan con mayor profundidad (aunque muy teóricos) y brindan un mayor conocimiento de fondo.

Session Management (SCWCD)

0 comentarios
Objetivos:
Section 4: Session Management
4.1- Write servlet code to store objects into a session object and retrieve objects from a session object.
4.2- Given a scenario describe the APIs used to access the session object, explain when the session object was created, and describe the mechanisms used to destroy the session object, and when it was destroyed.
4.3- Using session listeners, write code to respond to an event when an object is added to a session, and write code to respond to an event when a session object migrates from one VM to another.
4.4- Given a scenario, describe which session management mechanism the Web container could employ, how cookies might be used to manage sessions, how URL rewriting might be used to manage sessions, and write servlet code to perform URL rewriting.


Las sesiones en el protocolo HTTP
HTTP es un protocolo sin estado (stateless), cada petición al servidor web y su correspondiente respuesta es manejada como una transacción aislada. El servidor (HTTP) no tiene manera de determinar que una serie de peticiones provienen del mismo cliente.
Las sesiones, en una aplicación web, se utilizan para asociar las peticiones con el cliente. Una sesión comienza cuando un cliente desconocido envía la primera petición (que requiera crear una sesión) a la aplicación web. La misma finaliza, cuando el cliente la termina explícitamente o cuando se expira el tiempo de vida de la sesión (debido a que no se ha recibido una petición en un tiempo determinado).
La manera en que una aplicación web mantiene una sesión con el cliente es:
  • Cuando el servidor web recibe la primera petición de un cliente, el servidor inicia una sesión y le asigna un identificador único.
  • El cliente debe incluir este identificador único en cada petición subsecuente. El servidor revisa el identificador y asocia la petición con su correspondiente sesión.
Existen dos formas de implementar el soporte para sesiones, cookies y la sobreescritura de la URL.


javax.servlet.http.HttpSession
La API de servlets abstrae el concepto de sesión a través de esta interface. Cuando se inicia una sesión para un cliente, el contenedor de servlets instancia un objeto HttpSession. Los distintos servlets pueden utilizar este objeto para almacenar información relacionada al usuario y de esta manera mantener el estado del mismo. Existe un objeto HttpSession por cada sesión (o usuario). El contenedor de servlets se encarga de asociar una petición con su correspondiente objeto de sesión.
La interface javax.servlet.http.HttpServletRequest provee dos métodos para obtener la sesión:
  • HttpSession getSession (boolean create): Devuelve el correspondiente objeto sesión, o si no existe ninguna sesión y el parámetro sesión es true, crea una nueva sesión.
  • HttpSession getSession (): Método equivalente a invocar getSession (true).
Métodos de la interface HttpSession para el manejo de sus atributos:
  • void setAttribute (String name, Object value): Asocia el objeto pasado como parámetro a la sesión, y lo identifica a través del nombre.
  • Object getAttribute (String name): Devuelve el objeto asociado al nombre, o null en caso de no existir ninguno.

Manejando los eventos de sesión con las interfaces listener
En una aplicación web, cuando ocurren eventos importantes, se pueden recibir las notificaciones correspondientes a los mismos a través de las interfaces listener. Se crea una clase que implemente la interface listener correspondiente, y el contenedor de servlets invocará los métodos apropiados sobre un objeto (de esta clase) cuando ocurra algún evento.
La API de servlets define cuatro interfaces listener y dos eventos relacionados a las sesiones dentro de javax.servlet.http:
HttpSessionAttributeListener: Permite recibir notificaciones cuando se agrega, reemplaza, o elimina un atributo de un objeto HttpSession. La clase se debe especificar en el archivo web.xml. El contenedor de servlets solo crea una instancia, sobre la cual se invocaran los métodos para todas las sesiones.
  • void attributeAdded (HttpSessionBindingEvent sbe): Invocado cuando se agrega un atributo a una sesión.
  • void attributeRemoved (HttpSessionBindingEvent sbe): Invocado cuando se elimina un atributo.
  • void attributeReplaced (HttpSessionBindingEvent sbe): Invocado cuando se reemplaza un atributo.
HttpSessionBindingListener: Esta interface es implementada por aquellas clases cuyos objetos necesiten recibir notificaciones de cuando ellos son agregados y eliminados de una sesión. Esta clase no se especifica en el archivo web.xml. Cuando se agrega o elimina un objeto de una sesión, el contenedor revisa las interfaces que implementa. En caso de que el objeto implemente la interface HttpSessionBindingListener, el contenedor invoca el método correspondiente:
  • void valueBound (HttpSessionBindingEvent event): Notifica al objeto que está siendo asociado a una sesión.
  • void valueUnbound (HttpSessionBindingEvent event): Notifica al objeto que está siendo desasociado de una sesión.
HttpSessionListener: Esta interface se utiliza para recibir notificaciones de cuando una sesión se crea o se destruye. La clase que implemente dicha interface debe ser especificada en el archivo web.xml. Se crea una nueva instancia de esta clase, por cada nueva sesión creada. Posee los métodos:
  • void sessionCreated (HttpSessionEvent se): Se invoca cuando se crea una sesión.
  • void sessionDestroyed (HttpSessionEvent se): Se invoca cuando se destruye una sesión. Si dentro de este método se invoca el método getAttribute(), se lanza la excepción IllegalStateException.
HttpSessionActivationListener: (No se requiere para el examen) Esta interface se utiliza por los atributos de una sesión, para recibir notificaciones de cuando la sesión está siendo migrada a través de JVM’s en un ambiente distribuido.  De esta manera, los atributos contenidos en una sesión no se pierden, más allá de que exista más de una JVM ejecutando la aplicación. Posee los métodos:
  • void sessionDidActivate (HttpSessionEvent se): Se invoca justo después de que la sesión se activa.
  • void sessionWillPassivate (HttpSessionEvent se): Se invoca antes de desactivar la sesión.
Cerrar sesiones
La interface HttpSession provee el método:
  • void invalidate(): Cierra una sesión y desenlaza todos los objetos asociados a ella. Lanza la excepción IllegalStateException si la sesión ya ha sido cerrada.
Session timeout
El protocolo HTTP no provee ninguna señal de la terminación de una sesión en el servidor. Por este motivo, cuando el usuario no realiza ninguna acción en un período de tiempo determinado, el servidor cierra dicha sesión.
En el archivo web.xml, el elemento <session-timeout> contiene en minutos el tiempo de vida de una sesión. Un valor 0 o menor significa que la sesión nunca expirará.

    
        30
    

La interface HttpSession también posee los siguientes métodos:
  • void setMaxInactiveInterval (int seconds): Afecta solo a la sesión en la cual se invoca. Las demás, mantienen el tiempo especificado en el archivo web.xml.
  • void getMaxInactiveInterval ()
Existen dos inconsistencias entre estos modos de setear el timeout:
  1. El valor de elemento <session-timeout> se especifica en minutos, mientras que setMaxInactiveInterval() en segundos.
  2. El valor 0 o menos en el elemento <session-timeout> significa que la sesión nunca expirará, mientas que al método setMaxInactiveInterval() se le debe pasar un valor negativo (no 0) para conseguir el mismo comportamiento.

Utilización de cookies
En esta técnica, para enviar y recibir el identificador de una sesión, el contenedor de servlets utiliza los encabezados (headers) HTTP. Cuando se devuelve la respuesta, el contenedor agrega un encabezado especial que contiene el identificador de sesión. El cliente, el cual es típicamente un browser, extrae este encabezado especial, y lo almacena en la máquina local. Cuando se realiza otra petición, el cliente agrega automáticamente un encabezado que contiene el identificador de sesión almacenado. Este archivo almacenado se denomina cookie.
Cuando las cookies se encuentran deshabilitadas, el browser ignora cualquier encabezado que contenga cookies, y consecuentemente no envía ningún encabezado con cookies en la petición.


Sobreescritura de URL’s
Esta alternativa permite añadir, dentro de una respuesta, el identificador de sesión en todas las URL’s. De esta manera, cuando el usuario interactúe con el sitio, enviará automáticamente su identificador de sesión como parte de la petición.
Este mecanismo no es tranparente al desarrollador (a diferencia de las cookies). La interface HttpServletResponse provee los métodos:
  • String encodeURL (String url): Devuelve la url con el identificador de sesión adjuntado.
  • String encodeRedirectURL (String url): Idem anterior, pero se utiliza junto con el método sendRedirect().
Ambos métodos verifican si es necesario adjuntar el identificador. Si la petición contiene un encabezado de cookie, entonces las mismas están habilitadas en el browser cliente, y la sobreescritura de la url no es necesaria.
Se debe tener en cuenta que en la URL, el ID de la sesión se agrega luego del carácter ‘;’. Por ejemplo:
http://localhost:8080/scwcd/LoginServlet;jsessionid=1C9B3BAE94BE88AD45AA54B2A8AC0246?user=matias
Esto se debe a que jsessionid es parte del path info de la petición, y no es un parámetro de la misma. Este valor NO puede ser accedido a través del método HttpServletRequest.getParameter(“jsessionid”).


The Web Container Model - Filters (SCWCD)

1 comentarios
Objetivos:

Section 3: The Web Container Model (FILTERS)

3.3- Describe the Web container request processing model; write and configure a filter; create a request or response wrapper; and given a design problem, describe how to apply a filter or a wrapper.



Que es un filtro (filter)?
Para una aplicación web, un filtro es un componente web el cuál “filtra” las peticiones y respuestas que se realizan entre en cliente y el servidor. Estos filtros permiten monitorear los mensajes enviados antes de que los mismos alcancen su destino. La existencia de un filtro es transparente tanto al cliente como también al recurso (como puede ser un servlet).
También se puede emplear una cadena de filtros, en la cual los filtros se ejecutan uno seguido de otro (en cadena). Un filtro permite procesar una petición y pasarla (la petición procesada) al siguiente filtro de la cadena. Similarmente, cada filtro se ejecutará en orden inverso procesando la respuesta antes de que sea devuelta al cliente.

Como trabaja la filtración
Cuando el contenedor de servlets recibe una petición a un recurso, se verifica la existencia de filtros asociados al recurso. Si existe algún filtro asociado, el contenedor dirige la petición al filtro en vez de al recurso. Luego de que el filtro procesa la petición, realiza una de las siguientes acciones:
  • Genera la respuesta, por el mismo, y se la retorna al cliente.
  • Pasa la petición (modificada o no) al siguiente filtro de la cadena (si existe) o al recurso.
  • Dirige la petición a un recurso diferente.
Cuando se devuelve la respuesta desde el recurso, esta atraviesa el mismo conjunto de filtros en orden inverso. Cada filtro en la cadena puede modificar la respuesta.

La API de filtros (Filter API)
Interfaces del paquete javax.servlet:

javax.servlet.Filter: Todos los filtros deben implementar esta interface. Define tres métodos:
  • void init (FilterConfig) throws ServletException: El contenedor de servlets invoca este método sobre una instancia solo una vez. La implementación típica de este método es almacenar la instancia FilterConfig, para luego ser utilizada. Este método es una analogía del método init(ServletConfig) de la interface Servlet.
  • void doFilter (ServletRequest, ServletResponse, FilterChain) throws ServletException, IOException: El contenedor de servlets invoca este método para cada petición que sea mapeada con un filtro. Una implementación típica de una aplicación web, castea las instancias de ServletRequest y ServletResponse a sus correspondientes implementaciones del protocolo http, para luego realizar el procesamiento por el cual se creó el filtro. Este método es una analogía del método service(ServletRequest, ServletResponse) de la interface Servlet.
  • void destroy (): El contenedor de servlets invoca este método para liberar los recursos del filtro y realizar tareas de limpieza, antes de que el mismo sea eliminado.

javax.servlet.FilterChain: El contenedor de servlets provee una implementación para esta interface y pasa una instancia de la misma al método doFilter() del filtro. Posee solo un método:
  • void doFilter (ServletRequest, ServletResponse): Pasa la petición  al próximo componente en la cadena, otro filtro o el recurso original.

javax.servlet.FilterConfig: El contenedor de servlets provee una implementación para esta interface. Al igual que ServletConfig, la instancia se pasa a través del método init(FilterConfig). Esta interface provee métodos para acceder a los parámetros de inicialización de un filtro, y algunos otros datos:
  • String getFilterName (): Devuelve el nombre del filtro especificado en el archivo web.xml.
  • String getInitParameter (String): Devuelve el valor del parámetro especificado en el archivo web.xml.
  • Enumeration getInitParameterNames (): Devuelve una instancia Enumeration con los nombres de los parámetros de inicialización definidos en el archivo web.xml.
  • ServletContext getServletContext (): Devuelve la instancia de ServletContext asociada a la aplicación web.
Clases del paquete javax.servlet:
  • javax.servlet.ServletRequestWrapper
  • javax.servlet.ServletResponseWrapper
Clases del paquete javax.servlet.http:
  • javax.servlet.http.HttpServletRequestWapper
  • javax.servlet.http.HttpServletResponseWrapper
Estas últimas cuatro clases wrappers, funcionan de la misma manera. Toman una petición o una respuesta (ServletRequest o ServletResponse) en su constructor y delegan todas las invocaciones de métodos a ese objeto. Esto permite extender estas clases y sobrescribir cualquier método para personalizar un comportamiento.

Configurar un filtro
Para definir un filtro en el archivo web.xml, se debe utilizar los elementos <filter> y <filter-mapping>.
<!ELEMENT filter (icon?, filter-name, display-name?, description?, filter-class, init-param*) >
<!ELEMENT filter-mapping (filter-name, (url-pattern | servlet-name)) >

<filter>: Cada elemento de este tipo, introduce un nuevo filtro en la aplicación web. Este elemento puede contener varios elementos más. Algunos opcionales como: <icon>, <display-name> y <init-param>. Otros obligatorios como:
  • <filter-name>: Define el nombre del filtro dentro del archivo de configuración.
  • <filter-class>: Define la clase utilizada para instanciar el filtro.
<filter-mapping>: Al igual que <servlet-mapping>, este elemento asocia un filtro con un conjunto de URLs. Contiene los elementos:
  • <filter-name>: Identifica el filtro a asociar.
  • <url-pattern>: Se utiliza para aplicar el filtro a las peticiones que concuerden con el patrón URL.
  • <servlet-name>: Se utiliza para aplicar el filtro a todas las peticiones que se realicen al servlet asociado.
Solo puede existir un subelemento <url-pattern> o <servlet-name>, dentro un mismo <filter-mapping>.

Configurando cadenas de filtros
Las cadenas de filtros pueden ser configuradas utilizando múltiples elementos <filter-mapping>. Cuando el contenedor de servlets recibe una petición, este busca todos los mapeos de filtros que concuerdan la URI con el patrón URL. Este se considera el primer conjunto de filtros a aplicar al recurso. Luego, se buscan todos los mapeos de filtros con el nombre del servlet correspondiente. Este se convierte en el segundo conjunto de filtros en la cadena de filtros. En ambos conjuntos, el orden de los filtros se corresponde al orden de declaración de los mismos en el archivo web.xml.
El contenedor primero invoca a los filtros del primer conjunto antes que los del segundo.

Ejecución de filtros
Como la especificación de Servlets 2.4 permite invocar servlets de las siguientes maneras:
  • Como un resultado del método RequestDispatcher.forward().
  • Como un resultado del método RequestDispatcher.include().
  • En páginas de error.
Un filtro solo es invocado con peticiones entrantes (desde el cliente). Pero el archivo web.xml permite especificar los modos de invocación de un filtro:
<filter-mapping>
    <filter-name>AccessLog</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>
  • El elemento <filter-name> es obligatorio.
  • Se debe usar un elemento <url-pattern> o <servlet-name>, no se pueden usar ambos dentro de un mismo elemento <filter-mapping>.
  • Se pueden usar de 0 a 4 subelementos <dispatcher> dentro de un elemento <filter-mapping>.
  • Por defecto (si no se especifica ningún subelemento <dispatcher>) los filtros solo se aplican para peticiones entrantes a la aplicación. Es decir, solo el valor REQUEST es aplicado por defecto
  • Si el contenedor no puede encontrar el recurso solicitado por una petición, ningún filtro correspondiente a la misma se invoca. Los filtros solo se invocan si existe el recurso original.