|
package com.massahud.web.filter.pdf; |
|
|
|
import com.lowagie.text.DocumentException; |
|
import java.io.ByteArrayOutputStream; |
|
import java.io.IOException; |
|
import java.io.OutputStream; |
|
import java.io.OutputStreamWriter; |
|
import java.io.PrintWriter; |
|
import java.io.StringReader; |
|
import java.io.UnsupportedEncodingException; |
|
import java.net.URL; |
|
import java.net.URLEncoder; |
|
import javax.servlet.Filter; |
|
import javax.servlet.FilterChain; |
|
import javax.servlet.FilterConfig; |
|
import javax.servlet.ServletContext; |
|
import javax.servlet.ServletException; |
|
import javax.servlet.ServletRequest; |
|
import javax.servlet.ServletResponse; |
|
import javax.servlet.http.HttpServletRequest; |
|
import javax.servlet.http.HttpServletResponse; |
|
import javax.servlet.http.HttpServletResponseWrapper; |
|
import javax.xml.parsers.DocumentBuilder; |
|
import javax.xml.parsers.DocumentBuilderFactory; |
|
import javax.xml.parsers.ParserConfigurationException; |
|
import org.apache.log4j.Logger; |
|
import org.w3c.dom.Document; |
|
import org.xhtmlrenderer.pdf.ITextRenderer; |
|
import org.xhtmlrenderer.resource.FSEntityResolver; |
|
import org.xml.sax.InputSource; |
|
import org.xml.sax.SAXException; |
|
|
|
/** |
|
* Filtro que captura a resposta da aplicação e gera um pdf caso o parâmetro |
|
* media com valor pdf exista na requisição. Aceita também o parâmetro filename, |
|
* que faz com que o browser salve o arquivo com o nome informado ao invés de |
|
* criar um nome à partir da URL. |
|
*/ |
|
public class FiltroPdfRenderer implements Filter { |
|
|
|
private static final Logger logger = Logger.getLogger(FiltroPdfRenderer.class); |
|
public static final String NOME_PARAMETRO_MEDIA = "media"; |
|
public static final String MEDIA_PDF = "pdf"; |
|
public static final String NOME_PARAMETRO_ARQUIVO = "filename"; |
|
private DocumentBuilderFactory factory; |
|
private ServletContext ctx; |
|
|
|
@Override |
|
public void init(FilterConfig config) throws ServletException { |
|
// System.getProperties().setProperty("xr.util-logging.loggingEnabled", "true"); |
|
// XRLog.setLoggingEnabled(true); |
|
ctx = config.getServletContext(); |
|
factory = DocumentBuilderFactory.newInstance(); |
|
factory.setValidating(false); |
|
try { |
|
factory.setFeature("http://xml.org/sax/features/validation", false); |
|
factory.setFeature("http://xml.org/sax/features/namespaces", false); |
|
} catch (ParserConfigurationException ex) { |
|
logger.error("Erro ao inicializar filtro pdf: " + ex.getMessage(), ex); |
|
} |
|
|
|
try { |
|
|
|
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false); |
|
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); |
|
} catch (ParserConfigurationException ex) { |
|
logger.error("Erro ao inicializar filtro pdf: " + ex.getMessage(), ex); |
|
} |
|
|
|
factory.setIgnoringComments(true); |
|
} |
|
|
|
@Override |
|
public void doFilter(ServletRequest req, ServletResponse resp, |
|
FilterChain filterChain) throws IOException, ServletException { |
|
// Aplica o filtro apenas se o parâmetro media for pdf |
|
if (!MEDIA_PDF.equalsIgnoreCase(req.getParameter(NOME_PARAMETRO_MEDIA))) { |
|
filterChain.doFilter(req, resp); |
|
} else if (req instanceof HttpServletRequest && resp instanceof HttpServletResponse) { |
|
|
|
final HttpServletRequest request = (HttpServletRequest) req; |
|
final HttpServletResponse response = (HttpServletResponse) resp; |
|
|
|
//Capture the content for this request |
|
final ContentCaptureServletResponse capContent = new ContentCaptureServletResponse(response); |
|
filterChain.doFilter(request, capContent); |
|
|
|
try { |
|
// Gera o URI do documento, para que o renderer saiba os |
|
// endereços relativos de recursos de css e imagens |
|
final URL urlDocumento = new URL("http", "localhost", request.getLocalPort(), request.getRequestURI()); |
|
|
|
// Se o parâmetro filename for passado, coloca no cabeçalho respectivo o nome informado |
|
String filename = request.getParameter(NOME_PARAMETRO_ARQUIVO); |
|
if (filename == null) { |
|
final String contextPath = request.getContextPath().replaceAll(".*/", ""); |
|
filename = contextPath + ".pdf"; |
|
} |
|
// Parse do HTML gerado para um documento legível pelo XHTML renderer |
|
final StringReader contentReader = new StringReader(capContent.getContent()); |
|
final InputSource source = new InputSource(contentReader); |
|
|
|
source.setPublicId(filename); |
|
final ITextRenderer renderer = parse(source, urlDocumento); |
|
|
|
response.setContentType("application/pdf"); |
|
|
|
filename = URLEncoder.encode(filename, "UTF-8"); |
|
response.setHeader("Content-Disposition", "filename=\"" + filename + "\""); |
|
|
|
try (OutputStream browserStream = response.getOutputStream()) { |
|
renderer.createPDF(browserStream); |
|
} catch (DocumentException e) { |
|
throw new ServletException(e); |
|
} |
|
} catch (SAXException e) { |
|
throw new ServletException(e); |
|
} |
|
} |
|
} |
|
|
|
@Override |
|
public void destroy() { |
|
} |
|
|
|
private ITextRenderer parse(InputSource source, URL urlDocumento) throws SAXException, IOException, ServletException { |
|
try { |
|
DocumentBuilder documentBuilder = factory.newDocumentBuilder(); |
|
documentBuilder.setEntityResolver(FSEntityResolver.instance()); |
|
|
|
final Document xhtmlContent = documentBuilder.parse(source); |
|
final ITextRenderer renderer = new ITextRenderer(); |
|
renderer.setDocument(xhtmlContent, urlDocumento.toExternalForm()); |
|
|
|
JSFUserAgentCallback userAgent = new JSFUserAgentCallback(renderer.getOutputDevice(), ctx); |
|
userAgent.setBaseURL(urlDocumento.toExternalForm()); |
|
userAgent.setSharedContext(renderer.getSharedContext()); |
|
renderer.layout(); |
|
return renderer; |
|
} catch (ParserConfigurationException ex) { |
|
throw new ServletException(ex); |
|
} |
|
} |
|
|
|
private static class ContentCaptureServletResponse extends HttpServletResponseWrapper { |
|
|
|
private ByteArrayOutputStream contentBuffer; |
|
private PrintWriter writer; |
|
|
|
ContentCaptureServletResponse(HttpServletResponse originalResponse) { |
|
super(originalResponse); |
|
contentBuffer = new ByteArrayOutputStream(); |
|
try { |
|
writer = new PrintWriter(new OutputStreamWriter(contentBuffer, "UTF-8"), true); |
|
} catch (UnsupportedEncodingException ex) { |
|
throw new RuntimeException(ex.getMessage(), ex); |
|
} |
|
} |
|
|
|
@Override |
|
public PrintWriter getWriter() throws IOException { |
|
if (writer == null) { |
|
contentBuffer = new ByteArrayOutputStream(); |
|
writer = new PrintWriter(new OutputStreamWriter(contentBuffer, "UTF-8"), true); |
|
} |
|
return writer; |
|
} |
|
|
|
public String getContent() { |
|
try { |
|
writer.flush(); |
|
final String xhtmlContent = new String(contentBuffer.toByteArray(), "UTF-8"); |
|
return xhtmlContent; |
|
} catch (UnsupportedEncodingException ex) { |
|
throw new RuntimeException(ex.getMessage(), ex); |
|
} |
|
} |
|
} |
|
} |