All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.amashchenko.struts2.pdfstream.PdfStreamResult Maven / Gradle / Ivy

Go to download

Struts2 PDF Stream Plugin. This plugin allows to transform a view into a PDF stream and return it as a result from Action.

There is a newer version: 2.0.0
Show newest version
/*
 * 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