[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [mindfood] Sobre #34 de Effective Java [1]
Jose San Leandro wrote:
> ...
>
> Llegados a este punto, no sé si lo más conveniente sería tratar de manipular
> en runtime el bytecode, o bien proporcionar "parches" para las distintas
> implementaciones y versiones de los compiladores jsp. ¿Se os ocurre alguna
> alternativa más? ¿Qué opción os parece más acertada?
He echado un vistazo al servlet generado por Tomcat 4.1.12
correspondiente a un JSP cualquiera y el método _jspService tiene la
siguiente pinta (simplificando):
public void _jspService(...)
throws java.io.IOException, ServletException {
JspFactory _jspxFactory = null;
javax.servlet.jsp.PageContext pageContext = null;
JspWriter out = null;
try {
_jspxFactory = JspFactory.getDefaultFactory();
pageContext = _jspxFactory.getPageContext(this,
request, response, null, true, 8192, true);
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
out = pageContext.getOut();
(...)
}
Se observa que la instancia de PageContext proporciona acceso a
varios objetos implícitos (session, application, config) y en
particular al objeto implícito "out" (la implementación de Jasper de
JspWriter). A su vez, se utiliza la factoría JspFactory para obtener
la instancia de la implementación dependiente de la clase abstracta
PageContext.
Una posible solución pasaría sustituir la factoría por defecto de
Jasper por un JspFactory propio, utilizando el método estático
JspFactory.setDefaultFactory. Desgraciadamente, según el Javadoc los
autores JSP no tienen la capacidad de modificar la factoría por
defecto del contenedor:
"It is illegal for any principal other than the JSP Engine runtime
to call this method." [1]
Así pues esta vía parece plagada de obstáculos.
Creo que una solución más sencilla y apropiada a este problema la
proporcionaría el uso de filtros (javax.servlet.Filter [2]), un
nuevo elemento introducido por la especificación Servlet 2.3. Estos
componentes, a diferencia de los servlets, no tienen la capacidad de
generar una respuesta, pero pueden emplearse para interceptar las
peticiones antes de que alcancen al recurso destino y realizar algún
tipo de preproceso o postproceso.
Una posible aplicación sería pasar al servlet que genera la
respuesta un stream que suplante al original, impidiendo así que el
servlet cierre el stream original al finalizar. De esta manera, el
filtro tiene la oportunidad de modificar la respuesta del servlet
antes de enviarla al cliente. Para pasar al servlet el stream
suplente, el filtro utiliza una clase "envoltorio" de
HttpServletResponse que sobreescribe los métodos getWriter o
getOutputStream para devolver el nuevo stream. Como una línea de
código fuente vale más que mil palabras aquí va un ejemplo de lo que
propongo:
public class CustomOutputFilter
implements javax.servlet.Filter {
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
PrintWriter out = response.getWriter();
HttpServletResponse wrapper =
new MyResponseWrapper((HttpServletResponse)res)
chain.doFilter(req, wrapper);
PrintWriter outServlet = wrapper.getWriter();
// Read and process output from servlet
// transforming into whatYouWant
(...)
out.write(whatYouWant);
out.close();
}
}
public Class MyResponseWrapper
extends javax.servlet.http.HttpServletResponseWrapper {
private Writer out = null;
public MyResponseWrapper(HttpServletResponse res) {
super(res);
out = new MyWriter();
}
public PrintWriter getWriter() {
return new PrintWriter(out);
}
}
En el descriptor de despliegue se declara el filtro y se mapea
convenientemente (p.ej. para interceptar todas las peticiones a
páginas JSP):
<filter>
<filter-name>customOutputFilter</filter-name>
<filter-class>package.CustomOutputFilter</filter-class>
<init-param>
...
</init-param>
</filter>
<filter-mapping>
<filter-name>customOutputFilter</filter-name>
<url-pattern>/*.jsp</url-pattern>
</filter-mapping>
</filter-mapping>
Espero que esta pueda ser una solución para el problema que se te
presenta.
Un saludo,
Rafa
[1]
http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/jsp/JspFactory.html#setDefaultFactory(javax.servlet.jsp.JspFactory)
[2]
http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/Filter.html
--
Rafael Luque Leiva
Software Engineering Manager
Orange Soft - http://www.orange-soft.com
Urbanización Las Castañeras
Arroyo de los Combos, 26 bis
Arroyomolinos, E-28939 Madrid
Tel: +34 916 091 075
+34 605 511 847 (mobile)
Fax: +34 916 091 075
GnuPG Key ID: 0x4B9238A2