![JAR search and dependency download from the Maven repository](/logo.png)
com.amashchenko.struts2.pdfstream.PdfStreamResult Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of struts2-pdfstream-plugin Show documentation
Show all versions of struts2-pdfstream-plugin Show documentation
Struts2 PDF Stream Plugin. This plugin allows to transform a view into a PDF stream and return it as a result from Action.
/*
* Copyright 2014-2015 Aleksandr Mashchenko.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.amashchenko.struts2.pdfstream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URISyntaxException;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.dispatcher.StrutsResultSupport;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Entities.EscapeMode;
import org.xhtmlrenderer.pdf.ITextRenderer;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.BaseFont;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
/**
*
*
* This result transforms a view into a PDF stream. Default supported views are:
* HTML, JSP, FreeMarker template, Apache Tiles definition.
*
*
*
* This result type takes the following parameters:
*
*
*
*
*
* - contentDisposition - the content disposition header value for
* specifing the file name (default =
inline
, values are typically
* attachment;filename="document.pdf".
*
* - allowCaching if set to 'false' it will set the headers 'Pragma'
* and 'Cache-Control' to 'no-cahce', and prevent client from caching the
* content. (default =
true
)
*
* - renderer - name of the {@link ViewRenderer} bean which will be
* used to produce pdf stream. If not defined the {@link DefaultRenderer} will
* be used.
*
* - cssPaths - comma separated values of CSS files paths.
*
*
*
*
*
* Example JSP page:
*
*
*
* <result type="pdfstream">
* <param name="location">/WEB-INF/page.jsp</param>
* <param name="cssPaths">css/some.css, css/another.css</param>
* <param name="contentDisposition">attachment;filename="somepdf.pdf"</param>
* </result>
*
*
*
* Example FreeMarker template:
*
*
*
* <result type="pdfstream">
* <param name="location">/WEB-INF/template.ftl</param>
* <param name="renderer">freemarker</param>
* <param name="cssPaths">css/some.css, css/another.css</param>
* <param name="contentDisposition">attachment;filename="somepdf.pdf"</param>
* </result>
*
*
*
* @author Aleksandr Mashchenko
*
*/
public class PdfStreamResult extends StrutsResultSupport {
private static final long serialVersionUID = -1243295451653518563L;
/** Logger. */
private static final Logger LOG = LoggerFactory
.getLogger(PdfStreamResult.class);
private final static String PDF_MIME_TYPE = "application/pdf";
private final static String FONT_FILE_PATH = "/fonts/DejaVuSans.ttf";
private final static String FONT_STYLE_TAG = "";
private String contentDisposition = "inline";
private boolean allowCaching = true;
private String renderer;
private Set cssPathsSet;
@Inject
private Container container;
@Override
protected void doExecute(String finalLocation, ActionInvocation invocation)
throws Exception {
if (LOG.isDebugEnabled()) {
LOG.debug("In doExecute. finalLocation: " + finalLocation
+ ", renderer: " + renderer);
}
OutputStream os = null;
try {
final ActionContext actionContext = invocation
.getInvocationContext();
final HttpServletRequest request = (HttpServletRequest) actionContext
.get(HTTP_REQUEST);
final HttpServletResponse response = (HttpServletResponse) actionContext
.get(HTTP_RESPONSE);
final SimpleServletResponseWrapper responseWrapper = new SimpleServletResponseWrapper(
response);
final ServletContext servletContext = (ServletContext) actionContext
.get(SERVLET_CONTEXT);
ViewRenderer viewRenderer;
if (renderer == null) {
viewRenderer = container.getInstance(ViewRenderer.class);
} else {
viewRenderer = container.getInstance(ViewRenderer.class,
renderer);
}
if (viewRenderer == null) {
final String err = "Cannot get an instance of ViewRenderer with the name '"
+ renderer + "'.";
LOG.error(err);
throw new AssertionError(err);
}
// render view
viewRenderer.render(finalLocation, request, responseWrapper,
servletContext, actionContext.getLocale(),
invocation.getStack(), invocation.getAction());
// Set the content type
response.setContentType(PDF_MIME_TYPE);
// Set the content-disposition
if (contentDisposition != null) {
response.addHeader(
"Content-Disposition",
conditionalParse(contentDisposition, invocation));
}
// Set the cache control headers if necessary
if (!allowCaching) {
response.addHeader("Pragma", "no-cache");
response.addHeader("Cache-Control", "no-cache");
}
if (LOG.isTraceEnabled()) {
LOG.trace("Content before parsing:\n"
+ responseWrapper.toString());
}
// parse response wrapper
final Document document = parseContent(responseWrapper.toString());
final Element head = document.head();
// add CSS from cssPathsSet parameter
if (cssPathsSet != null && !cssPathsSet.isEmpty()) {
for (String css : cssPathsSet) {
// remove leading slash
if (css.startsWith("\\")) {
css = css.substring(1);
}
head.append("");
}
}
// add style for font family that supports unicode
head.append(FONT_STYLE_TAG);
final String content = document.html();
if (LOG.isTraceEnabled()) {
LOG.trace("Content after parsing:\n" + content);
}
// put pdf stream into response
createPdfStream(content, findBaseUrl(request),
response.getOutputStream());
} finally {
if (os != null) {
os.close();
}
}
}
Document parseContent(final String content) {
Document document = Jsoup.parse(content);
document.outputSettings().escapeMode(EscapeMode.xhtml);
document.outputSettings().syntax(Document.OutputSettings.Syntax.xml);
// remove script tags, they are not supported in pdf and can lead to
// not well formed document (e.g. <\/script> - escaped script tag)
document.select("script").remove();
return document;
}
private void createPdfStream(final String content, final String baseUrl,
final OutputStream outputStream) throws DocumentException,
IOException, URISyntaxException {
ITextRenderer renderer = new ITextRenderer();
// for unicode
renderer.getFontResolver().addFont(FONT_FILE_PATH, BaseFont.IDENTITY_H,
BaseFont.EMBEDDED);
renderer.setDocumentFromString(content, baseUrl);
renderer.layout();
renderer.createPDF(outputStream);
}
String findBaseUrl(final HttpServletRequest request) {
final String baseUrl;
if (request == null) {
baseUrl = "";
} else {
StringBuffer url = request.getRequestURL();
String uri = request.getRequestURI();
String ctx = request.getContextPath();
baseUrl = url.substring(0,
url.length() - uri.length() + ctx.length())
+ "/";
}
return baseUrl;
}
public void setCssPaths(final String cssPaths) {
cssPathsSet = stringToSet(cssPaths);
}
/**
* Converts comma separated string to LinkedHashSet.
*
* @param str
* Comma separated string.
* @return LinkedHashSet of strings.
*/
LinkedHashSet stringToSet(final String str) {
final LinkedHashSet set;
if (str == null || str.trim().isEmpty()) {
set = null;
} else {
set = new LinkedHashSet();
String[] split = str.split(",");
for (String s : split) {
String trimmed = s.trim();
if (!trimmed.isEmpty()) {
set.add(trimmed);
}
}
}
return set;
}
/**
* @param renderer
* the renderer to set
*/
public void setRenderer(String renderer) {
this.renderer = renderer;
}
/**
* @param contentDisposition
* the contentDisposition to set
*/
public void setContentDisposition(String contentDisposition) {
this.contentDisposition = contentDisposition;
}
/**
* @param allowCaching
* the allowCaching to set
*/
public void setAllowCaching(boolean allowCaching) {
this.allowCaching = allowCaching;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy