El mecanismo de manejo de peticiones de la capa de presentaci�n recibe muchos tipos diferentes de peticiones, cada uno de los cuales requiere varios tipos de procesamiento. Algunas peticiones simplemente requieren su reenvio al componente manejador apropiado, mientras que otras peticiones deben ser modificadas, auditadas, o descomprimidas antes de su procesamiento posterior.
�Problema:
Se requiere un pre-procesamiento y un post-procesamiento de unas peticiones o respuestas de un cliente Web.
Cuando una petici�n entra a una aplicaci�n Web, normalmente debe pasar varios test de entrada antes del estado de procesamiento principal. Por ejemplo,
- �Se ha autentificado el cliente?
- �Tiene el cliente una sesi�n v�lida?
- �La direcci�n IP del cliente es de una red conocida?
- �Viola alguna restricci�n el path de la petici�n?
- �Qu� codificaci�n usa el cliente para enviar los datos?
- �Soportamos el tipo de navegador del cliente?
Algunos de estos chequeos son tests, que resultan en una respuesta de si o no que determina si continuar� el procesamiento. Otros chequeos manipulan el stream de datos entrantes a una forma aceptable para el procesamiento.
La soluci�n b�sica consiste en un serie de chequeos condicionales, si cualquiera de ellos falla la petici�n se aborta. Las sentencias if/else anidadas son una estrategia est�ndar, pero esta soluci�n tiene fragilidad de c�digo y un estilo de programaci�n de copiar-y-pegar, porque el flujo del filtrado y la acci�n de los filtros se compila dentro de la aplicaci�n.
La clave para solventar este problema de una forma flexible y no obstrusiva es tener un mecanismo simple para a�adir y eliminar componentes de procesamiento, en el que cada componente completa una acci�n de filtrado espec�fica.
�Causas
- Procesamiento com�n, como un chequeo del esquema de codificaci�n de datos o la informaci�n de login de cada petici�n, completo por cada petici�n.
- Se desea la centralizaci�n de la l�gica com�n.
- Se deber�a facilitar la adici�n o eliminaci�n de sevicios sin afectar a los componentes existentes, para que se puedan utilizar en gran variedad de combinaciones, como
- Logging y autentificaci�n.
- Depuraci�n y transformaci�n de la salida para un cliente espec�fico
- Descomprensi�n y conversi�n del esquema de codificaci�n de la entrada.
�Soluci�n
Crear filtros conectables para procesar servicios comunes de una forma est�ndar sin requerir cambios en el c�digo principal del procesamiento de la petici�n. Los filtros interceptan las peticiones entrantes y las respuestas salientes, permitiendo un pre y post-procesamiento. Podemos a�adir y eliminar estos filtros a discrecci�n, sin necesitar cambios en nuestro c�digo existente.
Podemos, en efecto, decorar nuestro procesamiento principal con una veriedad de servicios comunes, como la seguridad, el logging, el depurado, etc. Estos filtros son componentes independientes del c�digo de la aplicaci�n principal, y pueden a�adirse o eliminarse de forma declarativa. Por ejemplo, se podr�a modificar un fichero de configuraci�n de despliegue para configurar una cadena de filtros. Cuando un cliente pide un recurso que corresponde con este mapeo de URL configurado, se procesa cada filtro de la cadena antes de poder invocar el recurso objetivo.
�Estructura
La siguiente figura representa el diagrama de clases del patr�n Intercepting Filter.

�Participantes y Responsabilidades
La siguiente figura representa el diagrama de la secuencia del patr�n Intercepting Filter.

�FilterManager
El FilterManager maneja el procesamiento de filtros. Crea el FilterChain con los filtros apropiados, en el orden correcto e inicia el procesamiento.
�FilterChain
El FilterChain es una collection ordenada de filtros indenpendientes.
�FilterOne, FilterTwo, FilterThree
Estos son los filtros individuales que son mapeados a un objetivo. El FilterChain coordina su procesamiento.
�Target
El Target es el recurso que el cliente ha solicitado.
�Estrategias
�Custom Filter
El filtro se implementa mediante una estrategia personalizada definida por el desarrollador. Esto es menos flexible y menos poderoso que la preferida Estrategia de Filtro Est�ndar que veremos en la siguiente secci�n y que s�lo est� disponible en contenedores que soporten la especificaci�n servlet 2.3. La estrategia de filtro personalizado es menos poderosa porque no puede proporcionar una envoltura para los objetos request y response de una forma est�ndar y portable. Adem�s, el objeto request no se puede modificar, y se debe introducir alguna suerte de mecanismo de buffer si los filtros son para controlar los streams de salida. Para implementar esta estrategia, el desarrollador podr�a utilizar el patr�n Decorator [GoF] para envolver los filtros alrededor de la l�gica principal del procesamiento de la petici�n. Por ejemplo, podr�a haber un filtro de depuraci�n que envuelva un filtro de autentificaci�n. Los siguientes fragmentos de c�digo muestran como se podr�an crear estos mecanismos de forma program�tia:
DebuggingFilter:
public class DebuggingFilter implements Processor {
private Processor target;
public DebuggingFilter(Processor myTarget) {
target = myTarget;
}
public void execute(ServletRequest req,
ServletResponse res) throws IOException,
ServletException {
//Do some filter processing here, such as
// displaying request parameters
target.execute(req, res);
}
}
CoreProcessor:
public class CoreProcessor implements Processor {
private Processor target;
public CoreProcessor() {
this(null);
}
public CoreProcessor(Processor myTarget) {
target = myTarget;
}
public void execute(ServletRequest req,
ServletResponse res) throws IOException,
ServletException {
//Do core processing here
}
}
En el controlador servlet, hemos delegado en un m�todo llamado processRequest para manejar las peticiones entrantes:
public void processRequest(ServletRequest req,
ServletResponse res)
throws IOException, ServletException {
Processor processors = new DebuggingFilter(
new AuthenticationFilter(new CoreProcessor()));
processors.execute(req, res);
//Then dispatch to next resource, which is probably
// the View to display
dispatcher.dispatch(req, res);
}
S�lo para prop�sitos de ejemplo, imagina que cada componente de procesamiento escribe en la salida est�ndar cuando se ejecuta. El siguiente ejemplo muestra la posible salida de la ejecuci�n:
Debugging filter preprocessing completed... Authentication filter processing completed... Core processing completed... Debugging filter post-processing completed...
Se ejecuta una cadena de procesadores en orden. Cada procesador, excepto el �ltimo de la cadena, se considera un filtro. En el componente procesador final es donde se encapsula el procesamiento principal que queremos completar para cada petici�n. Con este dise�o, necesitaremos cambiar el c�digo de la clase CoreProcessor, as� como cualquier clase de filtro, cuando querramos modificar la forma de manejar las peticiones.
La siguiente figura muestra un diagrama de secuencia que describe el flujo de control cuando se utiliza el c�digo de filtro de los ejemplos anteriores:

Observa que cuando usamos una implementaci�n de Decorator, cada filtro invoca directamente al siguiente filtro, aunque usando un interface gen�rico. De forma alternativa, esta estrategia se puede implementar utilizando un FilterManager y un FilterChain. En este caso, estos componentes manejan el procesamiento de los filtros y los filtros individuales no se comunican con ning�n otro filtro directamente. Este dise�o se aproxima al de una implementaci�n compatible con Servlet 2.3, aunque a�n as� es una estrategia personalizada. En el primero de los siguientes listado veremos la clase FilterManager que crea un objeto FilterChain.
public class FilterManager {
public void processFilter(Filter target,
javax.servlet.http.HttpServletRequest request,
javax.servlet.http.HttpServletResponse response)
throws javax.servlet.ServletException,
java.io.IOException {
FilterChain filterChain = new FilterChain();
// The filter manager builds the filter chain here
// if necessary
// Pipe request through Filter Chain
filterChain.processFilter(request, response);
//process target resource
target.execute(request, response);
}
}
El FilterChain a�ade filtros a la cadena en el orden apropiado (por brevedad lo hemos hecho en el constructor, pero normalmente se har�a en el lugar del comentario), procesa los filtros, y finalmente procesa el recurso objetivo:
public class FilterChain {
// filter chain
private Vector myFilters = new Vector();
// Creates new FilterChain
public FilterChain() {
// plug-in default filter services for example
// only. This would typically be done in the
// FilterManager, but is done here for example
// purposes
addFilter(new DebugFilter());
addFilter(new LoginFilter());
addFilter(new AuditFilter());
}
public void processFilter(
javax.servlet.http.HttpServletRequest request,
javax.servlet.http.HttpServletResponse response)
throws javax.servlet.ServletException,
java.io.IOException {
Filter filter;
// apply filters
Iterator filters = myFilters.iterator();
while (filters.hasNext())
{
filter = (Filter)filters.next();
// pass request & response through various
// filters
filter.execute(request, response);
}
}
public void addFilter(Filter filter) {
myFilters.add(filter);
}
}
En la siguiente figura podemos ver el diagrama de secuencia de este c�digo:

Esta estrategia no nos permite crear filtros que sean tan flexibles y poderosos como nos gustar�a. Por una cosa, los filtros se a�ade y eliminan program�ticamente. Aunque podr�amos escribir un mecanismo propietario para manejar la adici�n y eliminaci�n de filtros mediante un fichero de configuraci�n, a�n no tendr�amos ninguna forma de envolver los objetos request y response. Adem�s, sin un mecanismo de buffer sofisticado, esta estrategia no proporcionar� post-procesamiento flexible.
La Estrategia de Filtro Est�ndar proporciona soluciones para estos problemas, utilizando caracter�sticas de la especificaci�n Servlet 2.3, que proporciona una soluci�n est�ndar al dilema de los filtros.
�Standard Filter
Los filtros se controlan de forma declarativa utilizando un descriptor de despliegue, seg�n se describe en la especificaci�n Servlet 2.3. Esta especificaci�n incluye un mecanismo est�ndar para construir cadenas de filtos y poder a�adir y eliminar filtros de esa cadena de forma transparente. Los filtros se contruyen sobre interfaces, y se a�aden o eliminan de una forma declarativa modificando el descriptor de despliegue de una aplicaci�n Web.
Nuestro ejemplo para esta estrategia ser� crear un filtro que preprocese peticiones de cualquier tipo de codificaci�n como las que podr�amos manejar en el c�digo principal de manejo de peticiones. �Por qu� podr�a ser esto necesario? Los formularios HTML que incluyen un upload de ficheros utilizan un tipo de codificaci�n diferente a la mayor�a de formularios. As�, los datos del formulario que acompa�an al upload no est�n disponibles mediante simples llamadas a getParameter(). Por eso, creamos dos filtros que preprocesen las peticiones, traduciendo todos los tipos de codificaci�n en un s�lo formato consistente. El formato que elegimos es hacer que todos los datos del formulario est�n disponibles como atributos de la petici�n.
Un fitlro maneja la forma de codificaci�n est�ndar para el tipo application/x-www-form-urlencoded y el otro maneja el tipo de codificaci�n menos com�n multipart/form-data, que se utiliza en los formularios que incluyen uploads. Los filtros traducen todos los datos del formulario en atributos de la petici�n, para que el mecanismo principal de manejo de peticiones pueda trabajar con todas las peticiones de la misma manera. en lugar de hacerlo con los casos especiales de las diferentes codificaciones.
El siguiente ejemplo muestra un filtro que traduce las peticiones utilizando el esquema de codificaci�n de formularios est�ndar:
public class StandardEncodeFilter
extends BaseEncodeFilter {
// Creates new StandardEncodeFilter
public StandardEncodeFilter() { }
public void doFilter(javax.servlet.ServletRequest
servletRequest,javax.servlet.ServletResponse
servletResponse,javax.servlet.FilterChain
filterChain)
throws java.io.IOException,
javax.servlet.ServletException {
String contentType =
servletRequest.getContentType();
if ((contentType == null) ||
contentType.equalsIgnoreCase(
"application/x-www-form-urlencoded")) {
translateParamsToAttributes(servletRequest,
servletResponse);
}
filterChain.doFilter(servletRequest,
servletResponse);
}
private void translateParamsToAttributes(
ServletRequest request, ServletResponse response)
{
Enumeration paramNames =
request.getParameterNames();
while (paramNames.hasMoreElements()) {
String paramName = (String)
paramNames.nextElement();
String [] values;
values = request.getParameterValues(paramName);
System.err.println("paramName = " + paramName);
if (values.length == 1)
request.setAttribute(paramName, values[0]);
else
request.setAttribute(paramName, values);
}
}
}
El ejemplo siguiente muestra el filtro que maneja las traduciones de las peticiones que utilizan el esquema de codificaci�n multipart.:
public class MultipartEncodeFilter extends
BaseEncodeFilter {
public MultipartEncodeFilter() { }
public void doFilter(javax.servlet.ServletRequest
servletRequest, javax.servlet.ServletResponse
servletResponse,javax.servlet.FilterChain
filterChain)
throws java.io.IOException,
javax.servlet.ServletException {
String contentType =
servletRequest.getContentType();
// Only filter this request if it is multipart
// encoding
if (contentType.startsWith(
"multipart/form-data")){
try {
String uploadFolder =
getFilterConfig().getInitParameter(
"UploadFolder");
if (uploadFolder == null) uploadFolder = ".";
/** The MultipartRequest class is:
* Copyright (C) 2001 by Jason Hunter
* <[email protected]>. All rights reserved.
**/
MultipartRequest multi = new
MultipartRequest(servletRequest,
uploadFolder,
1 * 1024 * 1024 );
Enumeration params =
multi.getParameterNames();
while (params.hasMoreElements()) {
String name = (String)params.nextElement();
String value = multi.getParameter(name);
servletRequest.setAttribute(name, value);
}
Enumeration files = multi.getFileNames();
while (files.hasMoreElements()) {
String name = (String)files.nextElement();
String filename = multi.getFilesystemName(name);
String type = multi.getContentType(name);
File f = multi.getFile(name);
// At this point, do something with the
// file, as necessary
}
}
catch (IOException e)
{
LogManager.logMessage(
"error reading or saving file"+ e);
}
} // end if
filterChain.doFilter(servletRequest,
servletResponse);
} // end method doFilter()
}
El c�digo de estos filtros se basa en la especificaci�n servlet 2.3. Tambi�n se usa un filtro base, desde el que descienden estos dos filtros. El filtro base mostrado en el siguiente ejemplo proporciona el comportamiento por defecto para los m�todos de retrollamada del filtro est�ndar:
public class BaseEncodeFilter implements
javax.servlet.Filter {
private javax.servlet.FilterConfig myFilterConfig;
public BaseEncodeFilter() { }
public void doFilter(
javax.servlet.ServletRequest servletRequest,
javax.servlet.ServletResponse servletResponse,
javax.servlet.FilterChain filterChain)
throws java.io.IOException,
javax.servlet.ServletException {
filterChain.doFilter(servletRequest,
servletResponse);
}
public javax.servlet.FilterConfig getFilterConfig()
{
return myFilterConfig;
}
public void setFilterConfig(
javax.servlet.FilterConfig filterConfig) {
myFilterConfig = filterConfig;
}
}
Abajo tenemos un extracto del descriptor de despliegue de la aplicaci�n Web que contiene este ejemplo. Muestra c�mo se registran estos dos filtros y luego los mapea a un recurso, en este caso un sencillo servlet de prueba.
.
.
.
<filter>
<filter-name>StandardEncodeFilter</filter-name>
<display-name>StandardEncodeFilter</display-name>
<description></description>
<filter-class> corepatterns.filters.encodefilter.
StandardEncodeFilter</filter-class>
</filter>
<filter>
<filter-name>MultipartEncodeFilter</filter-name>
<display-name>MultipartEncodeFilter</display-name>
<description></description>
<filter-class>corepatterns.filters.encodefilter.
MultipartEncodeFilter</filter-class>
<init-param>
<param-name>UploadFolder</param-name>
<param-value>/home/files</param-value>
</init-param>
</filter>
.
.
.
<filter-mapping>
<filter-name>StandardEncodeFilter</filter-name>
<url-pattern>/EncodeTestServlet</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>MultipartEncodeFilter</filter-name>
<url-pattern>/EncodeTestServlet</url-pattern>
</filter-mapping>
.
.
.
En la siguiente figura podemos ver el diagrama de secuencia de este ejemplo:

Los filtros StandardEncodeFilter y MultiPartEncodeFilter interceptan el control cuando un cliente hace una petici�n al servlet controlador. El contenedor acepta el rol de manejador de filtros y conduce el control a estos filtros llamando a sus m�todos doFilter. Despu�s de completar su procesamiento, cada filtro pasa el control al FilterChain que lo contiene, que est� instruido para ejecutar el siguiente filtro. Una vez que el control ha pasado por los dos filtros, el siguiente componente en recibir el control es el recurso objetivo real, en este caso el servlet controlador.
Los filtros, seg�n lo soporta la especificaci�n Servlet 2.3, tambi�n soportan la envoltura de los objetos request y response. Esta caracter�stica proporciona un mecanismo mucho m�s podereos que el que se puede construir utilizando la implementaci�n personlizada de la secci�n anterior. Por supuesto, tambi�n podr�amos construir una aproximaci�n h�brida combinando las dos estrategias.
�Base Filter
Un filtro base sirve como una superclase com�n para todos los filtros. Las caracter�sticas comunes se pueden encapsular en el filtro base y se pueden compartir entre todos los filtros. Por ejemplo, un filtro base es un buen lugar para incluir el comportamiento por defecto de los m�todos de retrollamada del contenedor, como hemos visto en la secci�n anterior. El siguiente fragmento de c�digo nos muestra c�mo hacer esto:
public class BaseEncodeFilter implements
javax.servlet.Filter {
private javax.servlet.FilterConfig myFilterConfig;
public BaseEncodeFilter() { }
public void doFilter(javax.servlet.ServletRequest
servletRequest,javax.servlet.ServletResponse
servletResponse, javax.servlet.FilterChain
filterChain) throws java.io.IOException,
javax.servlet.ServletException {
filterChain.doFilter(servletRequest,
servletResponse);
}
public javax.servlet.FilterConfig getFilterConfig() {
return myFilterConfig;
}
public void
setFilterConfig(javax.servlet.FilterConfig
filterConfig) {
myFilterConfig = filterConfig;
}
}
�Template Filter
Usar un filtro base del que descienden todos los dem�s permite a la clase base proporcionar la funcionalidad de Plantilla de M�todos [GoF]. En este caso, el filtro base se utiliza para dictar los pasos generales que debe completar cada filtro, aunque deja las especifidades de c�mo completar esos pasos en la subclase de cada filtro. Normalmente, esto se definir�a de forma burda, m�todos b�sicos que simplemente imponen una estructura limitada a cada plantilla. Esta estrategia tambi�n se puede combinar con cualquier otra estrategia de filtros. Los siguientes listados muestran como utilizar esta estrategia con la Estrategia de Filtro Declarado:
public abstract class TemplateFilter implements
javax.servlet.Filter {
private FilterConfig filterConfig;
public void setFilterConfig(FilterConfig fc) {
filterConfig=fc;
}
public FilterConfig getFilterConfig() {
return filterConfig;
}
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// Common processing for all filters can go here
doPreProcessing(request, response, chain);
// Common processing for all filters can go here
doMainProcessing(request, response, chain);
// Common processing for all filters can go here
doPostProcessing(request, response, chain);
// Common processing for all filters can go here
// Pass control to the next filter in the chain or
// to the target resource
chain.doFilter(request, response);
}
public void doPreProcessing(ServletRequest request,
ServletResponse response, FilterChain chain) {
}
public void doPostProcessing(ServletRequest request,
ServletResponse response, FilterChain chain) {
}
public abstract void doMainProcessing(ServletRequest
request, ServletResponse response, FilterChain
chain);
}
Dando esta definici�n de clase para TemplateFilter, cada filtro se implementa como una subclase que s�lo debe implementar el m�todo doMainProcessing. Estas subclases tienen la opci�n de implementar los otros tres m�todos si lo desean. Abajo tenemos un ejemplo de una subclase que implementa el m�todo obligatorio (dictado por nuestra plantilla de filtro) y el m�todo de preprocesamiento opcional.
public class DebuggingFilter extends TemplateFilter {
public void doPreProcessing(ServletRequest req,
ServletResponse res, FilterChain chain) {
//do some preprocessing here
}
public void doMainProcessing(ServletRequest req,
ServletResponse res, FilterChain chain) {
//do the main processing;
}
}
En la siguiente figura podemos ver el diagrama de secuencia de esta estrategia:

En el diagrama de secuencia, las subclases, como DebuggingFilter, definen el procesamiento sobreescribiendo el m�todo abstracto doMainProcessing, y, opcionalmente, doPreProcessing y doPostProcessing. As�, la plantilla de filtro impone una estructura para el procesamiento de todos los filtros, as� como proporciona un lugar para encapsular el c�digo que es com�n para cada filtro.
�Consecuencias
- Centraliza el Control con Controladores de Acoplamiento Ligero
Los filtros proporcionan un lugar centralaizado para controlar el procesamiento a trav�s de m�ltiples peticiones, como lo hace el controlador. Los filtros est�n mejor preparados para manejar las peticiones y respuestas para el control �ltimo por un recurso objetivo, como un controlador. Adem�s, un controlador frecuentemente junta el control de numerosos sevicios comunes y no relacionados, como la autentificaci�n, el login, la encriptaci�n, etc., mientras que los filtros nos permiten controladores de acoplamiento m�s ligero, que se pueden combinar. - Mejora la Reutilizaci�n
Los filtros promueven la limpieza del particionamiento de la aplicaci�n y aconsejan su reutilizaci�n. Estos interceptores conectables se a�aden y eliminan al c�digo existente de forma transparente y debido a su interface est�ndar, funcionan en cualquier combinaci�n y son reutilizables por varias presentaciones. - Configuraci�n Declarativa y Flexible
Se pueden combinar numerosos servicios en varias permutaciones sin tener que recompilar ni una sola vez el c�digo fuente. - La Compartici�n Informaci�n es Ineficiente
Compartir informaci�n entre filtros puede ser ineficiente, porque por definici�n todo filtro tiene acoplamiento ligero. Si se deben compartir grandes cantidades de informaci�n entre los filtros, esta aproximaci�n podr�a ser muy costosa.
�Patrones Relacionados
- Front Controller
El controlador resuelve algunos problemas similares, pero est� mejor dise�ado para manejar el procesamiento principal. - Decorator [GoF]
El patr�n Intercepting Filter est� relacionado con el patr�n Decorator, que proporciona envolturas conectables din�micamente. - Template Method [GoF]
El patr�n de Plantillas de M�todos se utiliza para implementar la Estrategia de Plantilla de Filtros. - Interceptor [POSA2]
El patr�n Intercepting Filter est� relacionado con el patron Interceptor, que permite que se pueden a�adir servicios de forma transparente y dispararlos autom�ticamente. - Pipes and Filters [POSA1]
El patr�n Intercepting Filter est� relacionado con el patr�n Pipes and Filters.