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

org.apache.struts2.result.StreamResult Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.struts2.result;

import com.opensymphony.xwork2.ActionInvocation;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * 
 * 

* A custom Result type for sending raw data (via an InputStream) directly to the * HttpServletResponse. Very useful for allowing users to download content. *

* *

* This result type takes the following parameters: *

* * *
    * *
  • contentType - the stream mime-type as sent to the web browser * (default = text/plain).
  • * *
  • contentLength - the stream length in bytes (the browser displays a * progress bar).
  • * *
  • contentDisposition - the content disposition header value for * specifing the file name (default = inline, values are typically * attachment;filename="document.pdf".
  • * *
  • inputName - the name of the InputStream property from the chained * action (default = inputStream).
  • * *
  • bufferSize - the size of the buffer to copy from input to output * (default = 1024).
  • * *
  • 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) * *
  • contentCharSet if set to a string, ';charset=value' will be added to the * content-type header, where value is the string set. If set to an expression, the result * of evaluating the expression will be used. If not set, then no charset will be set on * the header
  • *
* *

These parameters can also be set by exposing a similarly named getter method on your Action. For example, you can * provide getContentType() to override that parameter for the current action.

* * *

* Example: *

* *
 * <result name="success" type="stream">
 *   <param name="contentType">image/jpeg</param>
 *   <param name="inputName">imageStream</param>
 *   <param name="contentDisposition">attachment;filename="document.pdf"</param>
 *   <param name="bufferSize">1024</param>
 * </result>
 * 
* */ public class StreamResult extends StrutsResultSupport { private static final long serialVersionUID = -1468409635999059850L; protected static final Logger LOG = LogManager.getLogger(StreamResult.class); public static final String DEFAULT_PARAM = "inputName"; protected String contentType = "text/plain"; protected String contentLength; protected String contentDisposition = "inline"; protected String contentCharSet ; protected String inputName = "inputStream"; protected InputStream inputStream; protected int bufferSize = 1024; protected boolean allowCaching = true; public StreamResult() { super(); } public StreamResult(InputStream in) { this.inputStream = in; } /** * @return Returns the whether or not the client should be requested to allow caching of the data stream. */ public boolean getAllowCaching() { return allowCaching; } /** * Set allowCaching to false to indicate that the client should be requested not to cache the data stream. * This is set to false by default * * @param allowCaching Enable caching. */ public void setAllowCaching(boolean allowCaching) { this.allowCaching = allowCaching; } /** * @return Returns the bufferSize. */ public int getBufferSize() { return (bufferSize); } /** * @param bufferSize The bufferSize to set. */ public void setBufferSize(int bufferSize) { this.bufferSize = bufferSize; } /** * @return Returns the contentType. */ public String getContentType() { return (contentType); } /** * @param contentType The contentType to set. */ public void setContentType(String contentType) { this.contentType = contentType; } /** * @return Returns the contentLength. */ public String getContentLength() { return contentLength; } /** * @param contentLength The contentLength to set. */ public void setContentLength(String contentLength) { this.contentLength = contentLength; } /** * @return Returns the Content-disposition header value. */ public String getContentDisposition() { return contentDisposition; } /** * @param contentDisposition the Content-disposition header value to use. */ public void setContentDisposition(String contentDisposition) { this.contentDisposition = contentDisposition; } /** * @return Returns the charset specified by the user */ public String getContentCharSet() { return contentCharSet; } /** * @param contentCharSet the charset to use on the header when sending the stream */ public void setContentCharSet(String contentCharSet) { this.contentCharSet = contentCharSet; } /** * @return Returns the inputName. */ public String getInputName() { return (inputName); } /** * @param inputName The inputName to set. */ public void setInputName(String inputName) { this.inputName = inputName; } /** * @see StrutsResultSupport#doExecute(java.lang.String, com.opensymphony.xwork2.ActionInvocation) */ protected void doExecute(String finalLocation, ActionInvocation invocation) throws Exception { LOG.debug("Find the Response in context"); OutputStream oOutput = null; try { if (inputStream == null) { LOG.debug("Find the inputstream from the invocation variable stack"); inputStream = (InputStream) invocation.getStack().findValue(conditionalParse(inputName, invocation)); } if (inputStream == null) { String msg = ("Can not find a java.io.InputStream with the name [" + inputName + "] in the invocation stack. " + "Check the tag specified for this action."); LOG.error(msg); throw new IllegalArgumentException(msg); } HttpServletResponse oResponse = (HttpServletResponse) invocation.getInvocationContext().get(HTTP_RESPONSE); LOG.debug("Set the content type: {};charset{}", contentType, contentCharSet); if (contentCharSet != null && ! contentCharSet.equals("")) { oResponse.setContentType(conditionalParse(contentType, invocation)+";charset="+conditionalParse(contentCharSet, invocation)); } else { oResponse.setContentType(conditionalParse(contentType, invocation)); } LOG.debug("Set the content length: {}", contentLength); if (contentLength != null) { String _contentLength = conditionalParse(contentLength, invocation); int _contentLengthAsInt; try { _contentLengthAsInt = Integer.parseInt(_contentLength); if (_contentLengthAsInt >= 0) { oResponse.setContentLength(_contentLengthAsInt); } } catch(NumberFormatException e) { LOG.warn("failed to recognize {} as a number, contentLength header will not be set", _contentLength, e); } } LOG.debug("Set the content-disposition: {}", contentDisposition); if (contentDisposition != null) { oResponse.addHeader("Content-Disposition", conditionalParse(contentDisposition, invocation)); } LOG.debug("Set the cache control headers if necessary: {}", allowCaching); if (!allowCaching) { oResponse.addHeader("Pragma", "no-cache"); oResponse.addHeader("Cache-Control", "no-cache"); } oOutput = oResponse.getOutputStream(); LOG.debug("Streaming result [{}] type=[{}] length=[{}] content-disposition=[{}] charset=[{}]", inputName, contentType, contentLength, contentDisposition, contentCharSet); LOG.debug("Streaming to output buffer +++ START +++"); byte[] oBuff = new byte[bufferSize]; int iSize; while (-1 != (iSize = inputStream.read(oBuff))) { LOG.debug("Sending stream ... {}", iSize); oOutput.write(oBuff, 0, iSize); } LOG.debug("Streaming to output buffer +++ END +++"); // Flush oOutput.flush(); } finally { if (inputStream != null) { inputStream.close(); } if (oOutput != null) { oOutput.close(); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy